From df41a3a7dfe7f3bc69eabef3a4afe0e9f2a8d8e1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 09:14:54 -0400 Subject: DRTVWR-588: Finally ditch LL_USE_SYSTEM_RAND code in llrand.cpp. This conditional code hasn't been used since June 2008, possibly even earlier. --- indra/llcommon/llrand.cpp | 104 +++++++++++++++++----------------------------- 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index cb28a8f5c3..33afc50cf7 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -58,46 +58,14 @@ * to restore uniform distribution. */ -// *NOTE: The system rand implementation is probably not correct. -#define LL_USE_SYSTEM_RAND 0 +static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); -#if LL_USE_SYSTEM_RAND -#include -#endif +// no default implementation, only specific F64 and F32 specializations +template +inline REAL ll_internal_random(); -#if LL_USE_SYSTEM_RAND -class LLSeedRand -{ -public: - LLSeedRand() - { -#if LL_WINDOWS - srand(LLUUID::getRandomSeed()); -#else - srand48(LLUUID::getRandomSeed()); -#endif - } -}; -static LLSeedRand sRandomSeeder; -inline F64 ll_internal_random_double() -{ -#if LL_WINDOWS - return (F64)rand() / (F64)RAND_MAX; -#else - return drand48(); -#endif -} -inline F32 ll_internal_random_float() -{ -#if LL_WINDOWS - return (F32)rand() / (F32)RAND_MAX; -#else - return (F32)drand48(); -#endif -} -#else -static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); -inline F64 ll_internal_random_double() +template <> +inline F64 ll_internal_random() { // *HACK: Through experimentation, we have found that dual core // CPUs (or at least multi-threaded processes) seem to @@ -108,15 +76,35 @@ inline F64 ll_internal_random_double() return rv; } +template <> +inline F32 ll_internal_random() +{ + return F32(ll_internal_random()); +} + +/*------------------------------ F64 aliases -------------------------------*/ +inline F64 ll_internal_random_double() +{ + return ll_internal_random(); +} + +F64 ll_drand() +{ + return ll_internal_random_double(); +} + +/*------------------------------ F32 aliases -------------------------------*/ inline F32 ll_internal_random_float() { - // The clamping rules are described above. - F32 rv = (F32)gRandomGenerator(); - if(!((rv >= 0.0f) && (rv < 1.0f))) return fmod(rv, 1.f); - return rv; + return ll_internal_random(); +} + +F32 ll_frand() +{ + return ll_internal_random_float(); } -#endif +/*-------------------------- clamped random range --------------------------*/ S32 ll_rand() { return ll_rand(RAND_MAX); @@ -130,42 +118,28 @@ S32 ll_rand(S32 val) return rv; } -F32 ll_frand() -{ - return ll_internal_random_float(); -} - -F32 ll_frand(F32 val) +template +REAL ll_grand(REAL val) { // The clamping rules are described above. - F32 rv = ll_internal_random_float() * val; + REAL rv = ll_internal_random() * val; if(val > 0) { - if(rv >= val) return 0.0f; + if(rv >= val) return REAL(); } else { - if(rv <= val) return 0.0f; + if(rv <= val) return REAL(); } return rv; } -F64 ll_drand() +F32 ll_frand(F32 val) { - return ll_internal_random_double(); + return ll_grand(val); } F64 ll_drand(F64 val) { - // The clamping rules are described above. - F64 rv = ll_internal_random_double() * val; - if(val > 0) - { - if(rv >= val) return 0.0; - } - else - { - if(rv <= val) return 0.0; - } - return rv; + return ll_grand(val); } -- cgit v1.2.3 From 0f8b8fd7a338272e3464e809b94eb0443d99e275 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 09:28:53 -0400 Subject: DRTVWR-588: Eliminate APR and Boost.Phoenix from NamedTempFile. NamedTempFile used to use APR calls to discover a suitable temp directory, synthesize a temp filename template, generate the unique file, write its content and ultimately delete it. This required a reference to gAPRPoolp as the default value of an optional constructor argument in case some usage demanded an alternative APR memory pool. It also used Boost.Phoenix placeholders to magically synthesize a callable. Replace APR calls with Boost.Filesystem; replace Boost.Phoenix with lambdas. Break out unique path generation logic as static NamedTempFile::temp_path(). In a nod to GitHub Actions builds, honor RUNNER_TEMP environment variable if set. test.cpp's RecordToTempFile need no longer pass an apr_pool_t* to NamedTempFile. NamedTempFile's constructor now accepts an optional suffix, making subclass NamedExtTempFile nearly trivial. It no longer needs to create or remove a symlink, for which it used to use APR calls. llprocess_test.cpp's NamedTempDir used to use Python's tempfile.mkdtemp() to create a temp directory, and apr_dir_remove() to destroy it. Replace both with NamedTempFile::temp_path() and Boost.Filesystem. Also add diagnostic output for LLProcess test failure. If llprocess_test cannot launch a child process, notice the APR_LOG environment variable recognized by our patched apr_suite to engage logging, and report the contents of that file. --- indra/llcommon/tests/llprocess_test.cpp | 70 ++++++++++---- indra/test/namedtempfile.h | 158 ++++++++++++-------------------- indra/test/test.cpp | 2 +- 3 files changed, 111 insertions(+), 119 deletions(-) diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 81449b4a42..c48d913069 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -151,8 +151,38 @@ struct PythonProcessLauncher /// Launch Python script; verify that it launched void launch() { - mPy = LLProcess::create(mParams); - tut::ensure(STRINGIZE("Couldn't launch " << mDesc << " script"), bool(mPy)); + try + { + mPy = LLProcess::create(mParams); + tut::ensure(STRINGIZE("Couldn't launch " << mDesc << " script"), bool(mPy)); + } + catch (const tut::failure&) + { + // On Windows, if APR_LOG is set, our version of APR's + // apr_create_proc() logs to the specified file. If this test + // failed, try to report that log. + const char* APR_LOG = getenv("APR_LOG"); + if (APR_LOG && *APR_LOG) + { + std::ifstream inf(APR_LOG); + if (! inf.is_open()) + { + LL_WARNS() << "Couldn't open '" << APR_LOG << "'" << LL_ENDL; + } + else + { + LL_WARNS() << "==============================" << LL_ENDL; + LL_WARNS() << "From '" << APR_LOG << "':" << LL_ENDL; + std::string line; + while (std::getline(inf, line)) + { + LL_WARNS() << line << LL_ENDL; + } + LL_WARNS() << "==============================" << LL_ENDL; + } + } + throw; + } } /// Run Python script and wait for it to complete. @@ -214,30 +244,26 @@ static std::string python_out(const std::string& desc, const CONTENT& script) class NamedTempDir: public boost::noncopyable { public: - // Use python() function to create a temp directory: I've found - // nothing in either Boost.Filesystem or APR quite like Python's - // tempfile.mkdtemp(). - // Special extra bonus: on Mac, mkdtemp() reports a pathname - // starting with /var/folders/something, whereas that's really a - // symlink to /private/var/folders/something. Have to use - // realpath() to compare properly. NamedTempDir(): - mPath(python_out("mkdtemp()", - "from __future__ import with_statement\n" - "import os.path, sys, tempfile\n" - "with open(sys.argv[1], 'w') as f:\n" - " f.write(os.path.normcase(os.path.normpath(os.path.realpath(tempfile.mkdtemp()))))\n")) - {} + mPath(NamedTempFile::temp_path()), + mCreated(boost::filesystem::create_directories(mPath)) + { + mPath = boost::filesystem::canonical(mPath); + } ~NamedTempDir() { - aprchk(apr_dir_remove(mPath.c_str(), gAPRPoolp)); + if (mCreated) + { + boost::filesystem::remove_all(mPath); + } } - std::string getName() const { return mPath; } + std::string getName() const { return mPath.string(); } private: - std::string mPath; + boost::filesystem::path mPath; + bool mCreated; }; /***************************************************************************** @@ -565,7 +591,13 @@ namespace tut " f.write(os.path.normcase(os.path.normpath(os.getcwd())))\n"); // Before running, call setWorkingDirectory() py.mParams.cwd = tempdir.getName(); - ensure_equals("os.getcwd()", py.run_read(), tempdir.getName()); + std::string expected{ tempdir.getName() }; +#if LL_WINDOWS + // SIGH, don't get tripped up by "C:" != "c:" -- + // but on the Mac, using tolower() fails because "/users" != "/Users"! + expected = utf8str_tolower(expected); +#endif + ensure_equals("os.getcwd()", py.run_read(), expected); } template<> template<> diff --git a/indra/test/namedtempfile.h b/indra/test/namedtempfile.h index 7d59cad32c..525a35000d 100644 --- a/indra/test/namedtempfile.h +++ b/indra/test/namedtempfile.h @@ -13,15 +13,16 @@ #define LL_NAMEDTEMPFILE_H #include "llerror.h" -#include "llapr.h" -#include "apr_file_io.h" +#include "llstring.h" +#include "stringize.h" #include -#include -#include -#include +#include +#include #include +#include #include #include +#include /** * Create a text file with specified content "somewhere in the @@ -31,134 +32,106 @@ class NamedTempFile: public boost::noncopyable { LOG_CLASS(NamedTempFile); public: - NamedTempFile(const std::string& pfx, const std::string& content, apr_pool_t* pool=gAPRPoolp): - mPool(pool) + NamedTempFile(const std::string_view& pfx, + const std::string_view& content, + const std::string_view& sfx=std::string_view("")) { - createFile(pfx, boost::phoenix::placeholders::arg1 << content); + createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx); } - // Disambiguate when passing string literal - NamedTempFile(const std::string& pfx, const char* content, apr_pool_t* pool=gAPRPoolp): - mPool(pool) + // Disambiguate when passing string literal -- unclear why a string + // literal should be ambiguous wrt std::string_view and Streamer + NamedTempFile(const std::string_view& pfx, + const char* content, + const std::string_view& sfx=std::string_view("")) { - createFile(pfx, boost::phoenix::placeholders::arg1 << content); + createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx); } // Function that accepts an ostream ref and (presumably) writes stuff to // it, e.g.: // (boost::phoenix::placeholders::arg1 << "the value is " << 17 << '\n') - typedef boost::function Streamer; + typedef std::function Streamer; - NamedTempFile(const std::string& pfx, const Streamer& func, apr_pool_t* pool=gAPRPoolp): - mPool(pool) + NamedTempFile(const std::string_view& pfx, + const Streamer& func, + const std::string_view& sfx=std::string_view("")) { - createFile(pfx, func); + createFile(pfx, func, sfx); } virtual ~NamedTempFile() { - ll_apr_assert_status(apr_file_remove(mPath.c_str(), mPool)); + boost::filesystem::remove(mPath); } - virtual std::string getName() const { return mPath; } + std::string getName() const { return mPath.string(); } void peep() { std::cout << "File '" << mPath << "' contains:\n"; - std::ifstream reader(mPath.c_str()); + boost::filesystem::ifstream reader(mPath); std::string line; while (std::getline(reader, line)) std::cout << line << '\n'; std::cout << "---\n"; } + static boost::filesystem::path temp_path(const std::string_view& pfx="", + const std::string_view& sfx="") + { + // This variable is set by GitHub actions and is the recommended place + // to put temp files belonging to an actions job. + const char* RUNNER_TEMP = getenv("RUNNER_TEMP"); + boost::filesystem::path tempdir{ + // if RUNNER_TEMP is set and not empty + (RUNNER_TEMP && *RUNNER_TEMP)? + boost::filesystem::path(RUNNER_TEMP) : // use RUNNER_TEMP if available + boost::filesystem::temp_directory_path()}; // else canonical temp dir + boost::filesystem::path tempname{ + // use filename template recommended by unique_path() doc, but + // with underscores instead of hyphens: some use cases involve + // temporary Python scripts + tempdir / stringize(pfx, "%%%%_%%%%_%%%%_%%%%", sfx) }; + return boost::filesystem::unique_path(tempname); + } + protected: - void createFile(const std::string& pfx, const Streamer& func) + void createFile(const std::string_view& pfx, + const Streamer& func, + const std::string_view& sfx) { // Create file in a temporary place. - const char* tempdir = NULL; - ll_apr_assert_status(apr_temp_dir_get(&tempdir, mPool)); - - // Construct a temp filename template in that directory. - char *tempname = NULL; - ll_apr_assert_status(apr_filepath_merge(&tempname, - tempdir, - (pfx + "XXXXXX").c_str(), - 0, - mPool)); - - // Create a temp file from that template. - apr_file_t* fp = NULL; - ll_apr_assert_status(apr_file_mktemp(&fp, - tempname, - APR_CREATE | APR_WRITE | APR_EXCL, - mPool)); - // apr_file_mktemp() alters tempname with the actual name. Not until - // now is it valid to capture as our mPath. - mPath = tempname; - + mPath = temp_path(pfx, sfx); + boost::filesystem::ofstream out{ mPath }; // Write desired content. - std::ostringstream out; - // Stream stuff to it. func(out); - - std::string data(out.str()); - apr_size_t writelen(data.length()); - ll_apr_assert_status(apr_file_write(fp, data.c_str(), &writelen)); - ll_apr_assert_status(apr_file_close(fp)); - llassert_always(writelen == data.length()); } - std::string mPath; - apr_pool_t* mPool; + boost::filesystem::path mPath; }; /** * Create a NamedTempFile with a specified filename extension. This is useful * when, for instance, you must be able to use the file in a Python import * statement. - * - * A NamedExtTempFile actually has two different names. We retain the original - * no-extension name as a placeholder in the temp directory to ensure - * uniqueness; to that we link the name plus the desired extension. Naturally, - * both must be removed on destruction. */ class NamedExtTempFile: public NamedTempFile { LOG_CLASS(NamedExtTempFile); public: - NamedExtTempFile(const std::string& ext, const std::string& content, apr_pool_t* pool=gAPRPoolp): - NamedTempFile(remove_dot(ext), content, pool), - mLink(mPath + ensure_dot(ext)) - { - linkto(mLink); - } + NamedExtTempFile(const std::string& ext, const std::string_view& content): + NamedTempFile(remove_dot(ext), content, ensure_dot(ext)) + {} // Disambiguate when passing string literal - NamedExtTempFile(const std::string& ext, const char* content, apr_pool_t* pool=gAPRPoolp): - NamedTempFile(remove_dot(ext), content, pool), - mLink(mPath + ensure_dot(ext)) - { - linkto(mLink); - } + NamedExtTempFile(const std::string& ext, const char* content): + NamedTempFile(remove_dot(ext), content, ensure_dot(ext)) + {} - NamedExtTempFile(const std::string& ext, const Streamer& func, apr_pool_t* pool=gAPRPoolp): - NamedTempFile(remove_dot(ext), func, pool), - mLink(mPath + ensure_dot(ext)) - { - linkto(mLink); - } - - virtual ~NamedExtTempFile() - { - ll_apr_assert_status(apr_file_remove(mLink.c_str(), mPool)); - } - - // Since the caller has gone to the trouble to create the name with the - // extension, that should be the name we return. In this class, mPath is - // just a placeholder to ensure that future createFile() calls won't - // collide. - virtual std::string getName() const { return mLink; } + NamedExtTempFile(const std::string& ext, const Streamer& func): + NamedTempFile(remove_dot(ext), func, ensure_dot(ext)) + {} static std::string ensure_dot(const std::string& ext) { @@ -175,7 +148,7 @@ public: { return ext; } - return std::string(".") + ext; + return "." + ext; } static std::string remove_dot(const std::string& ext) @@ -187,19 +160,6 @@ public: } return ext.substr(found); } - -private: - void linkto(const std::string& path) - { - // This method assumes that since mPath (without extension) is - // guaranteed by apr_file_mktemp() to be unique, then (mPath + any - // extension) is also unique. This is likely, though not guaranteed: - // files could be created in the same temp directory other than by - // this class. - ll_apr_assert_status(apr_file_link(mPath.c_str(), path.c_str())); - } - - std::string mLink; }; #endif /* ! defined(LL_NAMEDTEMPFILE_H) */ diff --git a/indra/test/test.cpp b/indra/test/test.cpp index bb48216b2b..9dd33c574d 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -100,7 +100,7 @@ public: RecordToTempFile(apr_pool_t* pPool) : LLError::Recorder(), boost::noncopyable(), - mTempFile("log", "", pPool), + mTempFile("log", ""), mFile(mTempFile.getName().c_str()) { } -- cgit v1.2.3 From 48759438b747c24b536cd099d65ab0c9ea720a38 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 09:53:01 -0400 Subject: DRTVWR-588: Remove Boost Phoenix, Bind and Assign from some tests. llsdserialize_test used Boost.Foreach, Boost.Function and Boost.Bind. llleap_test used Boost.Assign. Both used Boost.Phoenix. Replace Boost.Foreach with range 'for'. Replace Boost.Function with std::function. Replace Boost.Assign with initializer lists. Replace Boost.Bind and Boost.Phoenix with lambdas. --- indra/llcommon/tests/llleap_test.cpp | 251 ++++++++++++++-------------- indra/llcommon/tests/llsdserialize_test.cpp | 39 ++--- 2 files changed, 134 insertions(+), 156 deletions(-) diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 7ee36a9ea6..671873e982 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -17,8 +17,6 @@ // std headers #include // external library headers -#include -#include // other Linden headers #include "../test/lltut.h" #include "../test/namedtempfile.h" @@ -30,10 +28,6 @@ #include "stringize.h" #include "StringVec.h" -using boost::assign::list_of; - -StringVec sv(const StringVec& listof) { return listof; } - #if defined(LL_WINDOWS) #define sleep(secs) _sleep((secs) * 1000) @@ -104,7 +98,7 @@ namespace tut llleap_data(): reader(".py", // This logic is adapted from vita.viewerclient.receiveEvent() - boost::phoenix::placeholders::arg1 << + [](std::ostream& out){ out << "import re\n" "import os\n" "import sys\n" @@ -188,7 +182,7 @@ namespace tut "def request(pump, data):\n" " # we expect 'data' is a dict\n" " data['reply'] = _reply\n" - " send(pump, data)\n"), + " send(pump, data)\n";}), // Get the actual pathname of the NamedExtTempFile and trim off // the ".py" extension. (We could cache reader.getName() in a // separate member variable, but I happen to know getName() just @@ -213,14 +207,14 @@ namespace tut void object::test<1>() { set_test_name("multiple LLLeap instances"); - NamedTempFile script("py", - "import time\n" - "time.sleep(1)\n"); + NamedExtTempFile script("py", + "import time\n" + "time.sleep(1)\n"); LLLeapVector instances; instances.push_back(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))->getWeak()); + StringVec{PYTHON, script.getName()})->getWeak()); instances.push_back(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))->getWeak()); + StringVec{PYTHON, script.getName()})->getWeak()); // In this case we're simply establishing that two LLLeap instances // can coexist without throwing exceptions or bombing in any other // way. Wait for them to terminate. @@ -231,10 +225,10 @@ namespace tut void object::test<2>() { set_test_name("stderr to log"); - NamedTempFile script("py", - "import sys\n" - "sys.stderr.write('''Hello from Python!\n" - "note partial line''')\n"); + NamedExtTempFile script("py", + "import sys\n" + "sys.stderr.write('''Hello from Python!\n" + "note partial line''')\n"); StringVec vcommand{ PYTHON, script.getName() }; CaptureLog log(LLError::LEVEL_INFO); waitfor(LLLeap::create(get_test_name(), vcommand)); @@ -246,11 +240,11 @@ namespace tut void object::test<3>() { set_test_name("bad stdout protocol"); - NamedTempFile script("py", - "print('Hello from Python!')\n"); + NamedExtTempFile script("py", + "print('Hello from Python!')\n"); CaptureLog log(LLError::LEVEL_WARN); waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + StringVec{PYTHON, script.getName()})); ensure_contains("error log line", log.messageWith("invalid protocol"), "Hello from Python!"); } @@ -259,13 +253,13 @@ namespace tut void object::test<4>() { set_test_name("leftover stdout"); - NamedTempFile script("py", - "import sys\n" - // note lack of newline - "sys.stdout.write('Hello from Python!')\n"); + NamedExtTempFile script("py", + "import sys\n" + // note lack of newline + "sys.stdout.write('Hello from Python!')\n"); CaptureLog log(LLError::LEVEL_WARN); waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + StringVec{PYTHON, script.getName()})); ensure_contains("error log line", log.messageWith("Discarding"), "Hello from Python!"); } @@ -274,12 +268,12 @@ namespace tut void object::test<5>() { set_test_name("bad stdout len prefix"); - NamedTempFile script("py", - "import sys\n" - "sys.stdout.write('5a2:something')\n"); + NamedExtTempFile script("py", + "import sys\n" + "sys.stdout.write('5a2:something')\n"); CaptureLog log(LLError::LEVEL_WARN); waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + StringVec{PYTHON, script.getName()})); ensure_contains("error log line", log.messageWith("invalid protocol"), "5a2:"); } @@ -381,17 +375,17 @@ namespace tut set_test_name("round trip"); AckAPI api; Result result; - NamedTempFile script("py", - boost::phoenix::placeholders::arg1 << - "from " << reader_module << " import *\n" - // make a request on our little API - "request(pump='" << api.getName() << "', data={})\n" - // wait for its response - "resp = get()\n" - "result = '' if resp == dict(pump=replypump(), data='ack')\\\n" - " else 'bad: ' + str(resp)\n" - "send(pump='" << result.getName() << "', data=result)\n"); - waitfor(LLLeap::create(get_test_name(), sv(list_of(PYTHON)(script.getName())))); + NamedExtTempFile script("py", + [&](std::ostream& out){ out << + "from " << reader_module << " import *\n" + // make a request on our little API + "request(pump='" << api.getName() << "', data={})\n" + // wait for its response + "resp = get()\n" + "result = '' if resp == dict(pump=replypump(), data='ack')\\\n" + " else 'bad: ' + str(resp)\n" + "send(pump='" << result.getName() << "', data=result)\n";}); + waitfor(LLLeap::create(get_test_name(), StringVec{PYTHON, script.getName()})); result.ensure(); } @@ -419,38 +413,38 @@ namespace tut // iterations etc. in OS pipes and the LLLeap/LLProcess implementation. ReqIDAPI api; Result result; - NamedTempFile script("py", - boost::phoenix::placeholders::arg1 << - "import sys\n" - "from " << reader_module << " import *\n" - // Note that since reader imports llsd, this - // 'import *' gets us llsd too. - "sample = llsd.format_notation(dict(pump='" << - api.getName() << "', data=dict(reqid=999999, reply=replypump())))\n" - // The whole packet has length prefix too: "len:data" - "samplen = len(str(len(sample))) + 1 + len(sample)\n" - // guess how many messages it will take to - // accumulate BUFFERED_LENGTH - "count = int(" << BUFFERED_LENGTH << "/samplen)\n" - "print('Sending %s requests' % count, file=sys.stderr)\n" - "for i in range(count):\n" - " request('" << api.getName() << "', dict(reqid=i))\n" - // The assumption in this specific test that - // replies will arrive in the same order as - // requests is ONLY valid because the API we're - // invoking sends replies instantly. If the API - // had to wait for some external event before - // sending its reply, replies could arrive in - // arbitrary order, and we'd have to tick them - // off from a set. - "result = ''\n" - "for i in range(count):\n" - " resp = get()\n" - " if resp['data']['reqid'] != i:\n" - " result = 'expected reqid=%s in %s' % (i, resp)\n" - " break\n" - "send(pump='" << result.getName() << "', data=result)\n"); - waitfor(LLLeap::create(get_test_name(), sv(list_of(PYTHON)(script.getName()))), + NamedExtTempFile script("py", + [&](std::ostream& out){ out << + "import sys\n" + "from " << reader_module << " import *\n" + // Note that since reader imports llsd, this + // 'import *' gets us llsd too. + "sample = llsd.format_notation(dict(pump='" << + api.getName() << "', data=dict(reqid=999999, reply=replypump())))\n" + // The whole packet has length prefix too: "len:data" + "samplen = len(str(len(sample))) + 1 + len(sample)\n" + // guess how many messages it will take to + // accumulate BUFFERED_LENGTH + "count = int(" << BUFFERED_LENGTH << "/samplen)\n" + "print('Sending %s requests' % count, file=sys.stderr)\n" + "for i in range(count):\n" + " request('" << api.getName() << "', dict(reqid=i))\n" + // The assumption in this specific test that + // replies will arrive in the same order as + // requests is ONLY valid because the API we're + // invoking sends replies instantly. If the API + // had to wait for some external event before + // sending its reply, replies could arrive in + // arbitrary order, and we'd have to tick them + // off from a set. + "result = ''\n" + "for i in range(count):\n" + " resp = get()\n" + " if resp['data']['reqid'] != i:\n" + " result = 'expected reqid=%s in %s' % (i, resp)\n" + " break\n" + "send(pump='" << result.getName() << "', data=result)\n";}); + waitfor(LLLeap::create(get_test_name(), StringVec{PYTHON, script.getName()}), 300); // needs more realtime than most tests result.ensure(); } @@ -462,65 +456,62 @@ namespace tut { ReqIDAPI api; Result result; - NamedTempFile script("py", - boost::phoenix::placeholders::arg1 << - "import sys\n" - "from " << reader_module << " import *\n" - // Generate a very large string value. - "desired = int(sys.argv[1])\n" - // 7 chars per item: 6 digits, 1 comma - "count = int((desired - 50)/7)\n" - "large = ''.join('%06d,' % i for i in range(count))\n" - // Pass 'large' as reqid because we know the API - // will echo reqid, and we want to receive it back. - "request('" << api.getName() << "', dict(reqid=large))\n" - "try:\n" - " resp = get()\n" - "except ParseError as e:\n" - " # try to find where e.data diverges from expectation\n" - // Normally we'd expect a 'pump' key in there, - // too, with value replypump(). But Python - // serializes keys in a different order than C++, - // so incoming data start with 'data'. - // Truthfully, though, if we get as far as 'pump' - // before we find a difference, something's very - // strange. - " expect = llsd.format_notation(dict(data=dict(reqid=large)))\n" - " chunk = 40\n" - " for offset in range(0, max(len(e.data), len(expect)), chunk):\n" - " if e.data[offset:offset+chunk] != \\\n" - " expect[offset:offset+chunk]:\n" - " print('Offset %06d: expect %r,\\n'\\\n" - " ' get %r' %\\\n" - " (offset,\n" - " expect[offset:offset+chunk],\n" - " e.data[offset:offset+chunk]),\n" - " file=sys.stderr)\n" - " break\n" - " else:\n" - " print('incoming data matches expect?!', file=sys.stderr)\n" - " send('" << result.getName() << "', '%s: %s' % (e.__class__.__name__, e))\n" - " sys.exit(1)\n" - "\n" - "echoed = resp['data']['reqid']\n" - "if echoed == large:\n" - " send('" << result.getName() << "', '')\n" - " sys.exit(0)\n" - // Here we know echoed did NOT match; try to find where - "for i in range(count):\n" - " start = 7*i\n" - " end = 7*(i+1)\n" - " if end > len(echoed)\\\n" - " or echoed[start:end] != large[start:end]:\n" - " send('" << result.getName() << "',\n" - " 'at offset %s, expected %r but got %r' %\n" - " (start, large[start:end], echoed[start:end]))\n" - "sys.exit(1)\n"); + NamedExtTempFile script("py", + [&](std::ostream& out){ out << + "import sys\n" + "from " << reader_module << " import *\n" + // Generate a very large string value. + "desired = int(sys.argv[1])\n" + // 7 chars per item: 6 digits, 1 comma + "count = int((desired - 50)/7)\n" + "large = ''.join('%06d,' % i for i in range(count))\n" + // Pass 'large' as reqid because we know the API + // will echo reqid, and we want to receive it back. + "request('" << api.getName() << "', dict(reqid=large))\n" + "try:\n" + " resp = get()\n" + "except ParseError as e:\n" + " # try to find where e.data diverges from expectation\n" + // Normally we'd expect a 'pump' key in there, + // too, with value replypump(). But Python + // serializes keys in a different order than C++, + // so incoming data start with 'data'. + // Truthfully, though, if we get as far as 'pump' + // before we find a difference, something's very + // strange. + " expect = llsd.format_notation(dict(data=dict(reqid=large)))\n" + " chunk = 40\n" + " for offset in range(0, max(len(e.data), len(expect)), chunk):\n" + " if e.data[offset:offset+chunk] != \\\n" + " expect[offset:offset+chunk]:\n" + " print('Offset %06d: expect %r,\\n'\\\n" + " ' get %r' %\\\n" + " (offset,\n" + " expect[offset:offset+chunk],\n" + " e.data[offset:offset+chunk]),\n" + " file=sys.stderr)\n" + " break\n" + " else:\n" + " print('incoming data matches expect?!', file=sys.stderr)\n" + " send('" << result.getName() << "', '%s: %s' % (e.__class__.__name__, e))\n" + " sys.exit(1)\n" + "\n" + "echoed = resp['data']['reqid']\n" + "if echoed == large:\n" + " send('" << result.getName() << "', '')\n" + " sys.exit(0)\n" + // Here we know echoed did NOT match; try to find where + "for i in range(count):\n" + " start = 7*i\n" + " end = 7*(i+1)\n" + " if end > len(echoed)\\\n" + " or echoed[start:end] != large[start:end]:\n" + " send('" << result.getName() << "',\n" + " 'at offset %s, expected %r but got %r' %\n" + " (start, large[start:end], echoed[start:end]))\n" + "sys.exit(1)\n";}); waitfor(LLLeap::create(test_name, - sv(list_of - (PYTHON) - (script.getName()) - (stringize(size)))), + StringVec{PYTHON, script.getName(), stringize(size)}), 180); // try a longer timeout result.ensure(); } diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 5dbcf4c9b8..f46682e2d7 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -44,18 +44,10 @@ typedef U32 uint32_t; #include "llstring.h" #endif -#include "boost/range.hpp" -#include "boost/foreach.hpp" -#include "boost/function.hpp" -#include "boost/bind.hpp" -#include "boost/phoenix/bind/bind_function.hpp" -#include "boost/phoenix/core/argument.hpp" -using namespace boost::phoenix; - -#include "../llsd.h" -#include "../llsdserialize.h" +#include "llsd.h" +#include "llsdserialize.h" #include "llsdutil.h" -#include "../llformat.h" +#include "llformat.h" #include "../test/lltut.h" #include "../test/namedtempfile.h" @@ -1697,13 +1689,6 @@ namespace tut struct TestPythonCompatible { TestPythonCompatible(): - // Note the peculiar insertion of __FILE__ into this string. Since - // this script is being written into a platform-dependent temp - // directory, we can't locate indra/lib/python relative to - // Python's __file__. Use __FILE__ instead, navigating relative - // to this C++ source file. Use Python raw-string syntax so - // Windows pathname backslashes won't mislead Python's string - // scanner. import_llsd("import os.path\n" "import sys\n" "from llbase import llsd\n") @@ -1801,7 +1786,7 @@ namespace tut // helper for test<3> static void writeLLSDArray(std::ostream& out, const LLSD& array) { - BOOST_FOREACH(LLSD item, llsd::inArray(array)) + for (LLSD item: llsd::inArray(array)) { LLSDSerialize::toNotation(item, out); // It's important to separate with newlines because Python's llsd @@ -1841,21 +1826,22 @@ namespace tut // Create an llsdXXXXXX file containing 'data' serialized to // notation. NamedTempFile file("llsd", - // NamedTempFile's boost::function constructor + // NamedTempFile's std::function constructor // takes a callable. To this callable it passes the // std::ostream with which it's writing the // NamedTempFile. - boost::bind(writeLLSDArray, _1, cdata)); + [cdata](std::ostream& out){ writeLLSDArray(out, cdata); }); python("read C++ notation", - placeholders::arg1 << + [this, pydata, &file](std::ostream& out) { + out << import_llsd << "def parse_each(iterable):\n" " for item in iterable:\n" " yield llsd.parse(item)\n" << pydata << // Don't forget raw-string syntax for Windows pathnames. - "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n"); + "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n"; }); } template<> template<> @@ -1869,7 +1855,8 @@ namespace tut NamedTempFile file("llsd", ""); python("write Python notation", - placeholders::arg1 << + [this, &file](std::ostream& out) { + out << import_llsd << "DATA = [\n" " 17,\n" @@ -1881,9 +1868,9 @@ namespace tut "]\n" // Don't forget raw-string syntax for Windows pathnames. // N.B. Using 'print' implicitly adds newlines. - "with open(r'" << file.getName() << "', 'w') as f:\n" + "with open(r'" << file.getName() << "', 'wb') as f:\n" " for item in DATA:\n" - " print(llsd.format_notation(item).decode(), file=f)\n"); + " print(llsd.format_notation(item), file=f)\n"; }); std::ifstream inf(file.getName().c_str()); LLSD item; -- cgit v1.2.3 From 3fbb1a496dd4aaadc11727832f3ab0cc8c64950f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 10:03:16 -0400 Subject: DRTVWR-588: Remove some unused redundant timer functionality. LLEventTimer supported static run_every(), run_at() and run_after() methods to schedule future work. This can still be done by deriving from LLEventTimer, but is better accomplished with a WorkSchedule instance. These convenience methods, which encourage use of LLEventTimer insted of WorkSchedule, weren't used except by LLEventTimeout. Remove them and the LLEventTimer::Generic subclass used to implement them. Similarly, LLEventTimeout supported static post_every(), post_at() and post_after() methods based on LLEventTimer::run_every(), run_at() and run_after(). These weren't used either. LLRunner is a very old mechanism to schedule future work that seems to be unused. Research suggests that it's indirectly engaged only by LLDeferredChain, which isn't used. LLIOSleeper is tested but isn't otherwise used. Add a deprecation warning to llrun.h prior to excision. Also replace Boost.Bind with lambdas. --- indra/llcommon/lleventfilter.cpp | 34 ++++---------------- indra/llcommon/lleventfilter.h | 13 -------- indra/llcommon/lleventtimer.h | 69 +--------------------------------------- indra/llcommon/llrun.h | 11 +++++++ 4 files changed, 18 insertions(+), 109 deletions(-) diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index 4cded7f88e..14c9c51830 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -33,20 +33,19 @@ // STL headers // std headers // external library headers -#include // other Linden headers +#include "lldate.h" #include "llerror.h" // LL_ERRS +#include "lleventtimer.h" #include "llsdutil.h" // llsd_matches() #include "stringize.h" -#include "lleventtimer.h" -#include "lldate.h" /***************************************************************************** * LLEventFilter *****************************************************************************/ LLEventFilter::LLEventFilter(LLEventPump& source, const std::string& name, bool tweak): LLEventStream(name, tweak), - mSource(source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1))) + mSource(source.listen(getName(), [this](const LLSD& event){ return post(event); })) { } @@ -93,7 +92,7 @@ void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action) if (! mMainloop.connected()) { LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - mMainloop = mainloop.listen(getName(), boost::bind(&LLEventTimeoutBase::tick, this, _1)); + mMainloop = mainloop.listen(getName(), [this](const LLSD& event){ return tick(event); }); } } @@ -185,27 +184,6 @@ bool LLEventTimeout::countdownElapsed() const return mTimer.hasExpired(); } -LLEventTimer* LLEventTimeout::post_every(F32 period, const std::string& pump, const LLSD& data) -{ - return LLEventTimer::run_every( - period, - [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); }); -} - -LLEventTimer* LLEventTimeout::post_at(const LLDate& time, const std::string& pump, const LLSD& data) -{ - return LLEventTimer::run_at( - time, - [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); }); -} - -LLEventTimer* LLEventTimeout::post_after(F32 interval, const std::string& pump, const LLSD& data) -{ - return LLEventTimer::run_after( - interval, - [pump, data](){ LLEventPumps::instance().obtain(pump).post(data); }); -} - /***************************************************************************** * LLEventBatch *****************************************************************************/ @@ -311,7 +289,7 @@ bool LLEventThrottleBase::post(const LLSD& event) // timeRemaining tells us how much longer it will be until // mInterval seconds since the last flush() call. At that time, // flush() deferred events. - alarmActionAfter(timeRemaining, boost::bind(&LLEventThrottleBase::flush, this)); + alarmActionAfter(timeRemaining, [this](){ flush(); }); } } return false; @@ -349,7 +327,7 @@ void LLEventThrottleBase::setInterval(F32 interval) // and if mAlarm is running, reset that too if (alarmRunning()) { - alarmActionAfter(timeRemaining, boost::bind(&LLEventThrottleBase::flush, this)); + alarmActionAfter(timeRemaining, [this](){ flush(); }); } } } diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 7613850fb2..437a4826d4 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -214,19 +214,6 @@ public: LLEventTimeout(); LLEventTimeout(LLEventPump& source); - /// using LLEventTimeout as namespace for free functions - /// Post event to specified LLEventPump every period seconds. Delete - /// returned LLEventTimer* to cancel. - static LLEventTimer* post_every(F32 period, const std::string& pump, const LLSD& data); - /// Post event to specified LLEventPump at specified future time. Call - /// LLEventTimer::getInstance(returned pointer) to check whether it's still - /// pending; if so, delete the pointer to cancel. - static LLEventTimer* post_at(const LLDate& time, const std::string& pump, const LLSD& data); - /// Post event to specified LLEventPump after specified interval. Call - /// LLEventTimer::getInstance(returned pointer) to check whether it's still - /// pending; if so, delete the pointer to cancel. - static LLEventTimer* post_after(F32 interval, const std::string& pump, const LLSD& data); - protected: virtual void setCountdown(F32 seconds); virtual bool countdownElapsed() const; diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index dbbfe0c6e6..b5d40a0622 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -24,7 +24,7 @@ * $/LicenseInfo$ */ -#ifndef LL_EVENTTIMER_H +#ifndef LL_EVENTTIMER_H #define LL_EVENTTIMER_H #include "stdtypes.h" @@ -47,76 +47,9 @@ public: static void updateClass(); - /// Schedule recurring calls to generic callable every period seconds. - /// Returns a pointer; if you delete it, cancels the recurring calls. - template - static LLEventTimer* run_every(F32 period, const CALLABLE& callable); - - /// Schedule a future call to generic callable. Returns a pointer. - /// CAUTION: The object referenced by that pointer WILL BE DELETED once - /// the callback has been called! LLEventTimer::getInstance(pointer) (NOT - /// pointer->getInstance(pointer)!) can be used to test whether the - /// pointer is still valid. If it is, deleting it will cancel the - /// callback. - template - static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable); - - /// Like run_at(), but after a time delta rather than at a timestamp. - /// Same CAUTION. - template - static LLEventTimer* run_after(F32 interval, const CALLABLE& callable); - protected: LLTimer mEventTimer; F32 mPeriod; - -private: - template - class Generic; }; -template -class LLEventTimer::Generic: public LLEventTimer -{ -public: - // making TIME generic allows engaging either LLEventTimer constructor - template - Generic(const TIME& time, bool once, const CALLABLE& callable): - LLEventTimer(time), - mOnce(once), - mCallable(callable) - {} - BOOL tick() override - { - mCallable(); - // true tells updateClass() to delete this instance - return mOnce; - } - -private: - bool mOnce; - CALLABLE mCallable; -}; - -template -LLEventTimer* LLEventTimer::run_every(F32 period, const CALLABLE& callable) -{ - // return false to schedule recurring calls - return new Generic(period, false, callable); -} - -template -LLEventTimer* LLEventTimer::run_at(const LLDate& time, const CALLABLE& callable) -{ - // return true for one-shot callback - return new Generic(time, true, callable); -} - -template -LLEventTimer* LLEventTimer::run_after(F32 interval, const CALLABLE& callable) -{ - // one-shot callback after specified interval - return new Generic(interval, true, callable); -} - #endif //LL_EVENTTIMER_H diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index d610f86234..ebad5f3eaa 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -34,6 +34,17 @@ class LLRunnable; +////////////////////////////////////////////////////////////////////////////// +// DEPRECATION WARNING +// LLRunner is one of several mostly redundant ways to schedule future +// callbacks on the main thread. It seems to be unused in the current viewer. +// addRunner() is only called by LLPumpIO::sleepChain(). +// sleepChain() is only called by LLIOSleeper and LLIOSleep. +// LLIOSleeper is referenced only by tests. +// LLIOSleep is only called by LLDeferredChain. +// LLDeferredChain isn't referenced at all. +////////////////////////////////////////////////////////////////////////////// + /** * @class LLRunner * @brief This class manages a set of LLRunnable objects. -- cgit v1.2.3 From f24172d23d900bd6f9d10bb648107bbf4a755aaf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 10:34:40 -0400 Subject: DRTVWR-588: Correct typo in deprecation warning. --- indra/llcommon/llrun.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index ebad5f3eaa..27e4a43a8d 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -38,7 +38,7 @@ class LLRunnable; // DEPRECATION WARNING // LLRunner is one of several mostly redundant ways to schedule future // callbacks on the main thread. It seems to be unused in the current viewer. -// addRunner() is only called by LLPumpIO::sleepChain(). +// addRunnable() is only called by LLPumpIO::sleepChain(). // sleepChain() is only called by LLIOSleeper and LLIOSleep. // LLIOSleeper is referenced only by tests. // LLIOSleep is only called by LLDeferredChain. -- cgit v1.2.3 From 931a2fd63de2de417adbe3e02d55af7a459bca36 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 11:23:02 -0400 Subject: DRTVWR-588: print(file=) to binary file still requires str argument. Use f.writelines((bytes, b'\n')) instead. --- indra/llcommon/tests/llsdserialize_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index f46682e2d7..efd7dc9852 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1867,10 +1867,9 @@ namespace tut "lines.''',\n" "]\n" // Don't forget raw-string syntax for Windows pathnames. - // N.B. Using 'print' implicitly adds newlines. "with open(r'" << file.getName() << "', 'wb') as f:\n" " for item in DATA:\n" - " print(llsd.format_notation(item), file=f)\n"; }); + " f.writelines((llsd.format_notation(item), b'\n'))\n"; }); std::ifstream inf(file.getName().c_str()); LLSD item; -- cgit v1.2.3 From 36ed0e98ea7bd591a798a4373e8aa78a8fca4d14 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 11:42:09 -0400 Subject: DRTVWR-588: Try harder to normalize Windows pathames to compare. --- indra/llcommon/tests/llprocess_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index c48d913069..56dc2e4fa9 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -260,6 +260,7 @@ public: } std::string getName() const { return mPath.string(); } + std::string getNormalName() const { return mPath.lexically_normal().string(); } private: boost::filesystem::path mPath; @@ -591,7 +592,7 @@ namespace tut " f.write(os.path.normcase(os.path.normpath(os.getcwd())))\n"); // Before running, call setWorkingDirectory() py.mParams.cwd = tempdir.getName(); - std::string expected{ tempdir.getName() }; + std::string expected{ tempdir.getNormalName() }; #if LL_WINDOWS // SIGH, don't get tripped up by "C:" != "c:" -- // but on the Mac, using tolower() fails because "/users" != "/Users"! -- cgit v1.2.3 From b5fe9c476943807aa7526f67dd648b5ad250824b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 11:45:34 -0400 Subject: DRTVWR-588: To write b'\n' in Python source, use "b'\\n'" --- indra/llcommon/tests/llsdserialize_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index efd7dc9852..bb469f0686 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1869,7 +1869,7 @@ namespace tut // Don't forget raw-string syntax for Windows pathnames. "with open(r'" << file.getName() << "', 'wb') as f:\n" " for item in DATA:\n" - " f.writelines((llsd.format_notation(item), b'\n'))\n"; }); + " f.writelines((llsd.format_notation(item), b'\\n'))\n"; }); std::ifstream inf(file.getName().c_str()); LLSD item; -- cgit v1.2.3 From dc8f2ae2ba1a1348f86f412df7f769e6cc2fe541 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Aug 2023 17:01:56 -0400 Subject: DRTVWR-588: Try even harder to normalize Windows pathnames (SIGHH) --- indra/llcommon/tests/llprocess_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 56dc2e4fa9..ece567f40e 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -260,7 +260,7 @@ public: } std::string getName() const { return mPath.string(); } - std::string getNormalName() const { return mPath.lexically_normal().string(); } + std::string getNormalName() const { return mPath.lexically_normal().make_preferred().string(); } private: boost::filesystem::path mPath; -- cgit v1.2.3 From b5cba166b7bd6859fe3c7a0d81d7177cb79c74bd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 12 Sep 2023 08:48:17 -0400 Subject: SL-18837: GH-built apr_suite no longer includes apriconv. We had to switch to APR's partially-supported CMake builds, but apriconv has no upstream CMake config. --- indra/cmake/APR.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake index 8a0939c92c..2dd221f69e 100644 --- a/indra/cmake/APR.cmake +++ b/indra/cmake/APR.cmake @@ -16,7 +16,6 @@ if (WINDOWS) endif (LLCOMMON_LINK_SHARED) target_link_libraries( ll::apr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apr-1.lib - ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apriconv-1.lib ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}aprutil-1.lib ) elseif (DARWIN) -- cgit v1.2.3 From 5ed44adec58ba2ecb8dd073122bd8882fed30638 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 12 Sep 2023 09:29:26 -0400 Subject: DRTVWR-588: Fix a couple merge glitches in llsdserialize_test.cpp. --- indra/llcommon/tests/llsdserialize_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index c87deb8ffe..341b0d5609 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1948,7 +1948,7 @@ namespace tut { writeLLSDArray(serialize, out, cdata); }); python("read C++ " + desc, - [this, pydata, &file](std::ostream& out) { + [pydata, &file](std::ostream& out) { out << import_llsd << "from functools import partial\n" @@ -2062,7 +2062,7 @@ namespace tut NamedTempFile file("llsd", ""); python("Python " + pyformatter, - [this, &file](std::ostream& out) { + [pyformatter, &file](std::ostream& out) { out << import_llsd << "import struct\n" @@ -2081,7 +2081,7 @@ namespace tut " for item in DATA:\n" " serialized = llsd." << pyformatter << "(item)\n" " f.write(lenformat.pack(len(serialized)))\n" - " f.write(serialized)\n"); + " f.write(serialized)\n";}); std::ifstream inf(file.getName().c_str()); LLSD item; -- cgit v1.2.3 From 796085fc537e6bac7999e4b6624f02196eeaf4ad Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 12 Sep 2023 09:32:32 -0400 Subject: DRTVWR-588: Reimplement LLMainThreadTask based on WorkQueue instead of on LLEventTimer. LLEventTimer takes cycles from the main loop to run through the collection of pending LLEventTimers, checking each to see if we've reached its timestamp. But LLMainThreadTask does not require delay timing; it wants the main loop to service it ASAP. That's what the "mainloop" WorkQueue is for. But WorkQueue::waitForResult() forbids calls from a thread's default coroutine. While that restriction may still make sense in general, we specifically want to be able to pause LLMainThreadTask's caller, no matter what coroutine it's running on. Introduce WorkQueue::waitForResult_() that bypasses the check. --- indra/llcommon/llmainthreadtask.h | 58 ++++++++++----------------------------- indra/llcommon/workqueue.h | 40 +++++++++++++++++++-------- 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/indra/llcommon/llmainthreadtask.h b/indra/llcommon/llmainthreadtask.h index d509b687c0..dde6c20210 100644 --- a/indra/llcommon/llmainthreadtask.h +++ b/indra/llcommon/llmainthreadtask.h @@ -13,11 +13,8 @@ #if ! defined(LL_LLMAINTHREADTASK_H) #define LL_LLMAINTHREADTASK_H -#include "lleventtimer.h" #include "llthread.h" -#include "llmake.h" -#include -#include // std::result_of +#include "workqueue.h" /** * LLMainThreadTask provides a way to perform some task specifically on the @@ -28,18 +25,17 @@ * Instead of instantiating LLMainThreadTask, pass your invocable to its * static dispatch() method. dispatch() returns the result of calling your * task. (Or, if your task throws an exception, dispatch() throws that - * exception. See std::packaged_task.) + * exception.) * * When you call dispatch() on the main thread (as determined by * on_main_thread() in llthread.h), it simply calls your task and returns the * result. * - * When you call dispatch() on a secondary thread, it instantiates an - * LLEventTimer subclass scheduled immediately. Next time the main loop calls - * LLEventTimer::updateClass(), your task will be run, and LLMainThreadTask - * will fulfill a future with its result. Meanwhile the requesting thread - * blocks on that future. As soon as it is set, the requesting thread wakes up - * with the task result. + * When you call dispatch() on a secondary thread, it posts your task to + * gMainloopWork, the WorkQueue serviced by the main thread, using + * WorkQueue::waitForResult() to block the caller. Next time the main loop + * calls gMainloopWork.runFor(), your task will be run, and waitForResult() + * will return its result. */ class LLMainThreadTask { @@ -59,41 +55,15 @@ public: } else { - // It's essential to construct LLEventTimer subclass instances on - // the heap because, on completion, LLEventTimer deletes them. - // Once we enable C++17, we can use Class Template Argument - // Deduction. Until then, use llmake_heap(). - auto* task = llmake_heap(std::forward(callable)); - auto future = task->mTask.get_future(); - // Now simply block on the future. - return future.get(); + auto queue{ LL::WorkQueue::getInstance("mainloop") }; + // If this needs a null check and a message, please introduce a + // method in the .cpp file so consumers of this header don't drag + // in llerror.h. + // Use waitForResult_() so dispatch() can be used even from the + // calling thread's default coroutine. + return queue->waitForResult_(std::forward(callable)); } } - -private: - template - struct Task: public LLEventTimer - { - Task(CALLABLE&& callable): - // no wait time: call tick() next chance we get - LLEventTimer(0), - mTask(std::forward(callable)) - {} - BOOL tick() override - { - // run the task on the main thread, will populate the future - // obtained by get_future() - mTask(); - // tell LLEventTimer we're done (one shot) - return TRUE; - } - // Given arbitrary CALLABLE, which might be a lambda, how are we - // supposed to obtain its signature for std::packaged_task? It seems - // redundant to have to add an argument list to engage result_of, then - // add the argument list again to complete the signature. At least we - // only support a nullary CALLABLE. - std::packaged_task::type()> mTask; - }; }; #endif /* ! defined(LL_LLMAINTHREADTASK_H) */ diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index 70fd65bd0c..20fd15d0d5 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -12,7 +12,6 @@ #if ! defined(LL_WORKQUEUE_H) #define LL_WORKQUEUE_H -#include "llcoros.h" #include "llexception.h" #include "llinstancetracker.h" #include "threadsafeschedule.h" @@ -200,31 +199,51 @@ namespace LL } /** - * Post work to another WorkQueue to be run at a specified time, - * blocking the calling coroutine until then, returning the result to - * caller on completion. + * Post work, blocking the calling coroutine until then, returning the + * result to caller on completion. * * In general, we assume that each thread's default coroutine is busy * servicing its WorkQueue or whatever. To try to prevent mistakes, we * forbid calling waitForResult() from a thread's default coroutine. */ template - auto waitForResult(const TimePoint& time, CALLABLE&& callable); + auto waitForResult(CALLABLE&& callable) + { + return waitForResult(TimePoint::clock::now(), std::forward(callable)); + } /** - * Post work to another WorkQueue, blocking the calling coroutine - * until then, returning the result to caller on completion. + * Post work to be run at a specified time, blocking the calling + * coroutine until then, returning the result to caller on completion. * * In general, we assume that each thread's default coroutine is busy * servicing its WorkQueue or whatever. To try to prevent mistakes, we * forbid calling waitForResult() from a thread's default coroutine. */ template - auto waitForResult(CALLABLE&& callable) + auto waitForResult(const TimePoint& time, CALLABLE&& callable) { - return waitForResult(TimePoint::clock::now(), std::move(callable)); + checkCoroutine("waitForResult()"); + return waitForResult_(time, std::forward(callable)); } + /** + * Post work, blocking the calling coroutine until then, returning the + * result to caller on completion. + */ + template + auto waitForResult_(CALLABLE&& callable) + { + return waitForResult_(TimePoint::clock::now(), std::forward(callable)); + } + + /** + * Post work to be run at a specified time, blocking the calling + * coroutine until then, returning the result to caller on completion. + */ + template + auto waitForResult_(const TimePoint& time, CALLABLE&& callable); + /*--------------------------- worker API ---------------------------*/ /** @@ -561,9 +580,8 @@ namespace LL }; template - auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable) + auto WorkQueue::waitForResult_(const TimePoint& time, CALLABLE&& callable) { - checkCoroutine("waitForResult()"); // derive callable's return type so we can specialize for void return WaitForResult(callable)())>() (this, time, std::forward(callable)); -- cgit v1.2.3 From 24d405048fa0b9b26d1cb1d9e8ea8b113b867a14 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 12 Sep 2023 10:06:03 -0400 Subject: DRTVWR-588: Move LLSingleton dependency on LLMainThreadTask to .cpp. Introduce LLSingletonBase::getInstanceForSecondaryThread(), used both by LLSingleton and LLParamSingleton. Because it's a method of the non-template base class, because it's not itself a template method, getInstanceForSecondaryThread()'s definition can live in llsingleton.cpp. This is what calls LLMainThreadTask::dispatch(). To support LLParamSingleton, though, getInstanceForSecondaryThread() must be capable of handling arguments. For that, it accepts a nullary std::function returning the LLSingletonBase* of interest. Packing initParamSingleton() arguments into a nullary std::function to pass to getInstanceForSecondaryThread() sounds like a job for std::bind(). Unfortunately std::bind() has trouble forwarding int and string literals to a function that infers its argument types. To work around that, use boost::call_traits::param_type and a lambda with an explicit tuple. --- indra/llcommon/llsingleton.cpp | 31 ++++++++++++++++-- indra/llcommon/llsingleton.h | 72 ++++++++++++++++++++++++------------------ 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 6b1986d0e9..5c99048123 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -27,11 +27,12 @@ #include "linden_common.h" #include "llsingleton.h" +#include "llcoros.h" +#include "lldependencies.h" #include "llerror.h" #include "llerrorcontrol.h" -#include "lldependencies.h" #include "llexception.h" -#include "llcoros.h" +#include "llmainthreadtask.h" #include #include #include // std::cerr in dire emergency @@ -486,3 +487,29 @@ std::string LLSingletonBase::demangle(const char* mangled) { return LLError::Log::demangle(mangled); } + +LLSingletonBase* LLSingletonBase::getInstanceForSecondaryThread( + const std::string& name, + const std::string& method, + const std::function& getInstance) +{ + // Normally it would be the height of folly to reference-bind args into a + // lambda to be executed on some other thread! By the time that thread + // executed the lambda, the references would all be dangling, and Bad + // Things would result. But LLMainThreadTask::dispatch() promises to block + // the calling thread until the passed task has completed. So in this case + // we know the references will remain valid until the lambda has run, so + // we dare to bind references. + return LLMainThreadTask::dispatch( + [&name, &method, &getInstance](){ + // VERY IMPORTANT to call getInstance() on the main thread, + // rather than going straight to constructSingleton()! + // During the time window before mInitState is INITIALIZED, + // multiple requests might be queued. It's essential that, as + // the main thread processes them, only the FIRST such request + // actually constructs the instance -- every subsequent one + // simply returns the existing instance. + loginfos({name, "::", method, " on main thread"}); + return getInstance(); + }); +} diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 51ef514cf7..caecc3594f 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -25,16 +25,18 @@ #ifndef LLSINGLETON_H #define LLSINGLETON_H +#include #include #include +#include #include #include #include #include #include "mutex.h" #include "lockstatic.h" +#include "apply.h" #include "llthread.h" // on_main_thread() -#include "llmainthreadtask.h" class LLSingletonBase: private boost::noncopyable { @@ -134,6 +136,17 @@ protected: // internal wrapper around calls to cleanupSingleton() void cleanup_(); + // This method is where we dispatch to LLMainThreadTask to acquire the + // subclass LLSingleton instance when the first getInstance() call is from + // a secondary thread. We delegate to the .cpp file to untangle header + // circularity. It accepts a std::function referencing the subclass + // getInstance() method -- which can't be virtual because it's static; we + // don't yet have an instance! For messaging, it also accepts the name of + // the subclass and the subclass method. + static LLSingletonBase* getInstanceForSecondaryThread( + const std::string& name, const std::string& method, + const std::function& getInstance); + // deleteSingleton() isn't -- and shouldn't be -- a virtual method. It's a // class static. However, given only Foo*, deleteAll() does need to be // able to reach Foo::deleteSingleton(). Make LLSingleton (which declares @@ -555,19 +568,11 @@ public: // Per the comment block above, dispatch to the main thread. loginfos({classname(), "::getInstance() dispatching to main thread"}); - auto instance = LLMainThreadTask::dispatch( - [](){ - // VERY IMPORTANT to call getInstance() on the main thread, - // rather than going straight to constructSingleton()! - // During the time window before mInitState is INITIALIZED, - // multiple requests might be queued. It's essential that, as - // the main thread processes them, only the FIRST such request - // actually constructs the instance -- every subsequent one - // simply returns the existing instance. - loginfos({classname(), - "::getInstance() on main thread"}); - return getInstance(); - }); + auto instance = static_cast( + getInstanceForSecondaryThread( + classname(), + "getInstance()", + getInstance)); // record the dependency chain tracked on THIS thread, not the main // thread (consider a getInstance() overload with a tag param that // suppresses dep tracking when dispatched to the main thread) @@ -632,8 +637,14 @@ private: // Passes arguments to DERIVED_TYPE's constructor and sets appropriate // states, returning a pointer to the new instance. + // If we just let initParamSingleton_() infer its argument types, the + // compiler has trouble passing int and string literals. Use + // boost::call_traits::param_type to smooth parameter passing. This + // construction requires, though, that each invocation of this method + // explicitly specify template arguments, instead of inferring them. template - static DERIVED_TYPE* initParamSingleton_(Args&&... args) + static LLSingletonBase* initParamSingleton_( + typename boost::call_traits::param_type... args) { // In case racing threads both call initParamSingleton() at the same // time, serialize them. One should initialize; the other should see @@ -652,7 +663,7 @@ private: // on the main thread, simply construct instance while holding lock super::logdebugs({super::template classname(), "::initParamSingleton()"}); - super::constructSingleton(lk, std::forward(args)...); + super::constructSingleton(lk, args...); return lk->mInstance; } else @@ -665,20 +676,19 @@ private: lk.unlock(); super::loginfos({super::template classname(), "::initParamSingleton() dispatching to main thread"}); - // Normally it would be the height of folly to reference-bind - // 'args' into a lambda to be executed on some other thread! By - // the time that thread executed the lambda, the references would - // all be dangling, and Bad Things would result. But - // LLMainThreadTask::dispatch() promises to block until the passed - // task has completed. So in this case we know the references will - // remain valid until the lambda has run, so we dare to bind - // references. - auto instance = LLMainThreadTask::dispatch( - [&](){ - super::loginfos({super::template classname(), - "::initParamSingleton() on main thread"}); - return initParamSingleton_(std::forward(args)...); - }); + auto instance = static_cast( + super::getInstanceForSecondaryThread( + super::template classname(), + "initParamSingleton()", + // This lambda does what std::bind() is supposed to do -- + // but when the actual parameter is (e.g.) a string + // literal, type inference makes it fail. Apply param_type + // to each incoming type to make it work. + [args=std::tuple::param_type...>(args...)] + () + { + return LL::apply(initParamSingleton_, args); + })); super::loginfos({super::template classname(), "::initParamSingleton() returning on requesting thread"}); return instance; @@ -695,7 +705,7 @@ public: template static DERIVED_TYPE& initParamSingleton(Args&&... args) { - return *initParamSingleton_(std::forward(args)...); + return *static_cast(initParamSingleton_(args...)); } static DERIVED_TYPE* getInstance() -- cgit v1.2.3 From a33a9d29380e6c1a0a9cc539be309d47adef4acf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 25 Apr 2024 13:58:15 -0400 Subject: Adapt llimageworker_test for updated virtual method API. This was a broken test that got all the way to viewer release and the main branch. --- indra/llimage/tests/llimageworker_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index 0a97b739b0..ffcd7d257f 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -98,7 +98,7 @@ namespace tut done = res; *done = false; } - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32) { *done = true; } -- cgit v1.2.3 From 825c67612ce5ee6544055d82b337911050e86e75 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 25 Apr 2024 14:00:06 -0400 Subject: Add missing #include "stringize.h" Also change from boost::hof::is_invocable() to std::is_invocable(). --- indra/llcommon/lleventdispatcher.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index a82bc7a69b..3d7808ac31 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -35,7 +35,6 @@ #include #include #include -#include // until C++17, when we get std::is_invocable #include #include // std::function #include // std::unique_ptr @@ -48,6 +47,7 @@ #include "llevents.h" #include "llptrto.h" #include "llsdutil.h" +#include "stringize.h" class LLSD; @@ -99,7 +99,7 @@ public: template ::value + std::is_invocable::value >::type> void add(const std::string& name, const std::string& desc, @@ -296,7 +296,7 @@ public: */ template () + ! std::is_invocable() >::type> void add(const std::string& name, const std::string& desc, @@ -338,7 +338,7 @@ public: template::value && - ! boost::hof::is_invocable::value + ! std::is_invocable::value >::type> void add(const std::string& name, const std::string& desc, Function f, const LLSD& params, const LLSD& defaults=LLSD()); -- cgit v1.2.3 From 0bcbe6f850580306d3f665e459873adf736c37a2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 25 Apr 2024 14:01:50 -0400 Subject: Resolve WorkQueue::waitForResult() merge glitch. --- indra/llcommon/workqueue.h | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index 03c0494c1f..c4435cec40 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -115,33 +115,29 @@ namespace LL ARGS&&... args); /** - * Post work to be run at a specified time, blocking the calling - * coroutine until then, returning the result to caller on completion. - * Optional final argument is TimePoint for WorkSchedule. + * Post work, blocking the calling coroutine, returning the result to + * caller on completion. Optional final argument is TimePoint for + * WorkSchedule. * * In general, we assume that each thread's default coroutine is busy * servicing its WorkQueue or whatever. To try to prevent mistakes, we * forbid calling waitForResult() from a thread's default coroutine. */ template - auto waitForResult(CALLABLE&& callable, ARGS&&... args); - - /** - * Post work, blocking the calling coroutine until then, returning the - * result to caller on completion. - */ - template - auto waitForResult_(CALLABLE&& callable) + auto waitForResult(CALLABLE&& callable, ARGS&&... args) { - return waitForResult_(TimePoint::clock::now(), std::forward(callable)); + checkCoroutine("waitForResult()"); + return waitForResult_(std::forward(callable), + std::forward(args)...); } /** - * Post work to be run at a specified time, blocking the calling - * coroutine until then, returning the result to caller on completion. + * Post work, blocking the calling coroutine, returning the result to + * caller on completion. Optional final argument is TimePoint for + * WorkSchedule. */ - template - auto waitForResult_(const TimePoint& time, CALLABLE&& callable); + template + auto waitForResult_(CALLABLE&& callable, ARGS&&... args); /*--------------------------- worker API ---------------------------*/ @@ -634,7 +630,7 @@ namespace LL }; template - auto WorkQueueBase::waitForResult(CALLABLE&& callable, ARGS&&... args) + auto WorkQueueBase::waitForResult_(CALLABLE&& callable, ARGS&&... args) { // derive callable's return type so we can specialize for void return WaitForResult(callable)())>() -- cgit v1.2.3 From 9bf5fcd225ada9dcd63fc5710f58013e7839df09 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 26 Apr 2024 09:22:39 -0400 Subject: Remove unused newview/llcallbacklist.cpp: real one is in llcommon. newview/llcallbacklist.cpp has no corresponding .h file, it isn't referenced by newview/CMakeLists.txt, and its removal doesn't affect the build. See llcommon/llcallbacklist.{h,cpp} for the real functionality. (cherry picked from commit 8e53d6ff4c6594f014f456b0ba9ebf86ac91f6bc) --- indra/newview/llcallbacklist.cpp | 305 --------------------------------------- 1 file changed, 305 deletions(-) delete mode 100644 indra/newview/llcallbacklist.cpp diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp deleted file mode 100644 index 59ecbdd0ea..0000000000 --- a/indra/newview/llcallbacklist.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/** - * @file llcallbacklist.cpp - * @brief A simple list of callback functions to call. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llcallbacklist.h" -#include "lleventtimer.h" - -// Library includes -#include "llerror.h" - - -// -// Globals -// -LLCallbackList gIdleCallbacks; - -// -// Member functions -// - -LLCallbackList::LLCallbackList() -{ - // nothing -} - -LLCallbackList::~LLCallbackList() -{ -} - - -void LLCallbackList::addFunction( callback_t func, void *data) -{ - if (!func) - { - LL_ERRS() << "LLCallbackList::addFunction - function is NULL" << LL_ENDL; - return; - } - - // only add one callback per func/data pair - callback_pair_t t(func, data); - callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); - if (iter == mCallbackList.end()) - { - mCallbackList.push_back(t); - } -} - - -BOOL LLCallbackList::containsFunction( callback_t func, void *data) -{ - callback_pair_t t(func, data); - callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); - if (iter != mCallbackList.end()) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -BOOL LLCallbackList::deleteFunction( callback_t func, void *data) -{ - callback_pair_t t(func, data); - callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); - if (iter != mCallbackList.end()) - { - mCallbackList.erase(iter); - return TRUE; - } - else - { - return FALSE; - } -} - - -void LLCallbackList::deleteAllFunctions() -{ - mCallbackList.clear(); -} - - -void LLCallbackList::callFunctions() -{ - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); - } -} - -// Shim class to allow arbitrary boost::bind -// expressions to be run as one-time idle callbacks. -class OnIdleCallbackOneTime -{ -public: - OnIdleCallbackOneTime(nullary_func_t callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime* self = reinterpret_cast(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } -private: - nullary_func_t mCallable; -}; - -void doOnIdleOneTime(nullary_func_t callable) -{ - OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); -} - -// Shim class to allow generic boost functions to be run as -// recurring idle callbacks. Callable should return true when done, -// false to continue getting called. -class OnIdleCallbackRepeating -{ -public: - OnIdleCallbackRepeating(bool_func_t callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating* self = reinterpret_cast(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } -private: - bool_func_t mCallable; -}; - -void doOnIdleRepeating(bool_func_t callable) -{ - OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); -} - -class NullaryFuncEventTimer: public LLEventTimer -{ -public: - NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } - -private: - BOOL tick() - { - mCallable(); - return TRUE; - } - - nullary_func_t mCallable; -}; - -// Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds) -{ - new NullaryFuncEventTimer(callable, seconds); -} - -class BoolFuncEventTimer: public LLEventTimer -{ -public: - BoolFuncEventTimer(bool_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } -private: - BOOL tick() - { - return mCallable(); - } - - bool_func_t mCallable; -}; - -// Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds) -{ - new BoolFuncEventTimer(callable, seconds); -} - -#ifdef _DEBUG - -void test1(void *data) -{ - S32 *s32_data = (S32 *)data; - LL_INFOS() << "testfunc1 " << *s32_data << LL_ENDL; -} - - -void test2(void *data) -{ - S32 *s32_data = (S32 *)data; - LL_INFOS() << "testfunc2 " << *s32_data << LL_ENDL; -} - - -void -LLCallbackList::test() -{ - S32 a = 1; - S32 b = 2; - LLCallbackList *list = new LLCallbackList; - - LL_INFOS() << "Testing LLCallbackList" << LL_ENDL; - - if (!list->deleteFunction(NULL)) - { - LL_INFOS() << "passed 1" << LL_ENDL; - } - else - { - LL_INFOS() << "error, removed function from empty list" << LL_ENDL; - } - - // LL_INFOS() << "This should crash" << LL_ENDL; - // list->addFunction(NULL); - - list->addFunction(&test1, &a); - list->addFunction(&test1, &a); - - LL_INFOS() << "Expect: test1 1, test1 1" << LL_ENDL; - list->callFunctions(); - - list->addFunction(&test1, &b); - list->addFunction(&test2, &b); - - LL_INFOS() << "Expect: test1 1, test1 1, test1 2, test2 2" << LL_ENDL; - list->callFunctions(); - - if (list->deleteFunction(&test1, &b)) - { - LL_INFOS() << "passed 3" << LL_ENDL; - } - else - { - LL_INFOS() << "error removing function" << LL_ENDL; - } - - LL_INFOS() << "Expect: test1 1, test1 1, test2 2" << LL_ENDL; - list->callFunctions(); - - list->deleteAllFunctions(); - - LL_INFOS() << "Expect nothing" << LL_ENDL; - list->callFunctions(); - - LL_INFOS() << "nothing :-)" << LL_ENDL; - - delete list; - - LL_INFOS() << "test complete" << LL_ENDL; -} - -#endif // _DEBUG -- cgit v1.2.3 From c231c97eeefc484b74198ba86251054b7dc0e6bb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 2 May 2024 21:13:28 -0400 Subject: WIP: In llcallbacklist.h, add singleton LLLater for time delays. The big idea is to reduce the number of per-tick callbacks asking, "Is it time yet? Is it time yet?" We do that for LLEventTimer and LLEventTimeout. LLLater presents doAtTime(LLDate), with doAfterInterval() and doPeriodically() methods implemented using doAtTime(). All return handles. The free functions doAfterInterval() and doPeriodically() now forward to the corresponding LLLater methods. LLLater also presents isRunning(handle) and cancel(handle). LLLater borrows the tactic of LLEventTimer: while there's at least one running timer, it registers an LLCallbackList tick() callback to service ready timers. But instead of looping over all of them asking, "Are you ready?" it keeps them in a priority queue ordered by desired timestamp, and only touches those whose timestamp has been reached. Also, it honors a maximum time slice: once the ready timers have run for longer than the limit, it defers processing other ready timers to the next tick() call. The intent is to consume fewer cycles per tick() call, both by the management machinery and the timers themselves. Revamp LLCallbackList to accept C++ callables in addition to (classic C function pointer, void*) pairs. Make addFunction() return a handle (different than LLLater handles) that can be passed to a new deleteFunction() overload, since std::function instances can't be compared for equality. In fact, implement LLCallbackList using boost::signals2::signal, which provides almost exactly what we want. LLCallbackList continues to accept (function pointer, void*) pairs, but now we store a lambda that calls the function pointer with that void*. It takes less horsing around to create a C++ callable from a (function pointer, void*) pair than the other way around. For containsFunction() and deleteFunction(), such pairs are the keys for a lookup table whose values are handles. Instead of having a static global LLCallbackList gIdleCallbacks, make LLCallbackList an LLSingleton to guarantee initialization. For backwards compatibility, gIdleCallbacks is now a macro for LLCallbackList::instance(). Move doOnIdleOneTime() and doOnIdleRepeating() functions to LLCallbackList methods, but for backwards compatibility continue providing free functions. Reimplement LLEventTimer using LLLater::doPeriodically(). One implication is that LLEventTimer need no longer be derived from LLInstanceTracker, which we used to iterate over all instances every tick. Give it start() and stop() methods, since some subclasses (e.g. LLFlashTimer) used to call its member LLTimer's start() and stop(). Remove updateClass(): LLCallbackList::callFunctions() now takes care of that. Remove LLToastLifeTimer::start() and stop(), since LLEventTimer now provides those. Remove getRemainingTimeF32(), since LLLater does not (yet) provide that feature. While at it, make LLEventTimer::tick() return bool instead of BOOL, and change existing overrides. Make LLApp::stepFrame() call LLCallbackList::callFunctions() instead of LLEventTimer::updateClass(). We could have refactored LLEventTimer to use the mechanism now built into LLLater, but frankly the LLEventTimer API is rather clumsy. You MUST derive a subclass and override tick(), and you must instantiate your subclass on the heap because, when your tick() override returns false, LLEventTimer deletes its subclass instance. The LLLater API is simpler to use, and LLEventTimer is much simplified by using it. Merge lleventfilter.h's LLEventTimeoutBase into LLEventTimeout, and likewise merge LLEventThrottleBase into LLEventThrottle. The separation was for testability, but now that they're no longer based on LLTimer, it becomes harder to use dummy time for testing. Temporarily skip tests based on LLEventTimeoutBase and LLEventThrottleBase. Instead of listening for LLEventPump("mainloop") ticks and using LLTimer, LLEventTimeout now uses LLLater::doAfterInterval(). Instead of LLTimer and LLEventTimeout, LLEventThrottle likewise now uses LLLater::doAfterInterval(). Recast a couple local LLEventTimeout pre-lambda callable classes with lambdas. Dignify F64 with a new typedef LLDate::timestamp. LLDate heavily depends on that as its base time representation, but there are those who question use of floating-point for time. This is a step towards insulating us from any future change. --- indra/llcommon/llapp.cpp | 2 +- indra/llcommon/llcallbacklist.cpp | 324 +++++++++++++--------- indra/llcommon/llcallbacklist.h | 228 +++++++++++++-- indra/llcommon/lldate.cpp | 12 +- indra/llcommon/lldate.h | 8 +- indra/llcommon/llerrorlegacy.h | 32 --- indra/llcommon/lleventfilter.cpp | 138 +++------ indra/llcommon/lleventfilter.h | 129 +++------ indra/llcommon/lleventtimer.cpp | 39 +-- indra/llcommon/lleventtimer.h | 18 +- indra/llcommon/lllivefile.cpp | 2 +- indra/llcommon/tests/lleventfilter_test.cpp | 14 + indra/llcommon/tests/llmainthreadtask_test.cpp | 4 +- indra/llui/llflashtimer.cpp | 14 +- indra/llui/llflashtimer.h | 2 +- indra/newview/llappearancemgr.cpp | 5 +- indra/newview/lldonotdisturbnotificationstorage.h | 2 +- indra/newview/llfloaterlinkreplace.h | 2 +- indra/newview/llfloaterpreference.cpp | 2 +- indra/newview/llfloaterregionrestarting.h | 2 +- indra/newview/llfloateruipreview.cpp | 2 +- indra/newview/llimview.h | 2 +- indra/newview/lllocalbitmaps.h | 2 +- indra/newview/lllocalgltfmaterials.h | 2 +- indra/newview/llmediadataclient.h | 10 +- indra/newview/llpanelpeople.cpp | 6 +- indra/newview/llsetkeybinddialog.cpp | 2 +- indra/newview/llspeakers.h | 2 +- indra/newview/lltoast.cpp | 29 +- indra/newview/lltoast.h | 10 +- indra/newview/llviewermessage.cpp | 2 +- indra/newview/llviewerparcelmediaautoplay.h | 2 +- 32 files changed, 564 insertions(+), 486 deletions(-) delete mode 100644 indra/llcommon/llerrorlegacy.h diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 90d0c28eb1..5722f10f62 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -322,7 +322,7 @@ void LLApp::stepFrame() { LLFrameTimer::updateFrameTime(); LLFrameTimer::updateFrameCount(); - LLEventTimer::updateClass(); + LLCallbackList::instance().callFunctions(); mRunner.run(); } diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 9f23ce5317..7f7fdc7370 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -25,17 +25,14 @@ */ #include "llcallbacklist.h" -#include "lleventtimer.h" -#include "llerrorlegacy.h" - -// Globals -// -LLCallbackList gIdleCallbacks; // // Member functions // +/***************************************************************************** +* LLCallbackList +*****************************************************************************/ LLCallbackList::LLCallbackList() { // nothing @@ -45,186 +42,251 @@ LLCallbackList::~LLCallbackList() { } - -void LLCallbackList::addFunction( callback_t func, void *data) +LLCallbackList::handle_t LLCallbackList::addFunction( callback_t func, void *data) { if (!func) { - return; + return {}; } // only add one callback per func/data pair // if (containsFunction(func, data)) { - return; + return {}; } - - callback_pair_t t(func, data); - mCallbackList.push_back(t); + + auto handle = addFunction([func, data]{ func(data); }); + mLookup.emplace(callback_pair_t(func, data), handle); + return handle; } -bool LLCallbackList::containsFunction( callback_t func, void *data) +LLCallbackList::handle_t LLCallbackList::addFunction( const callable_t& func ) { - callback_pair_t t(func, data); - callback_list_t::iterator iter = find(func,data); - if (iter != mCallbackList.end()) - { - return TRUE; - } - else - { - return FALSE; - } + return mCallbackList.connect(func); } +bool LLCallbackList::containsFunction( callback_t func, void *data) +{ + return mLookup.find(callback_pair_t(func, data)) != mLookup.end(); +} bool LLCallbackList::deleteFunction( callback_t func, void *data) { - callback_list_t::iterator iter = find(func,data); - if (iter != mCallbackList.end()) + auto found = mLookup.find(callback_pair_t(func, data)); + if (found != mLookup.end()) { - mCallbackList.erase(iter); - return TRUE; + mLookup.erase(found); + deleteFunction(found->second); + return true; } else { - return FALSE; + return false; } } -inline -LLCallbackList::callback_list_t::iterator -LLCallbackList::find(callback_t func, void *data) +void LLCallbackList::deleteFunction( const handle_t& handle ) { - callback_pair_t t(func, data); - return std::find(mCallbackList.begin(), mCallbackList.end(), t); + handle.disconnect(); } void LLCallbackList::deleteAllFunctions() { - mCallbackList.clear(); + mCallbackList = {}; + mLookup.clear(); } - void LLCallbackList::callFunctions() { - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); - } + mCallbackList(); } -// Shim class to allow arbitrary boost::bind -// expressions to be run as one-time idle callbacks. -class OnIdleCallbackOneTime +LLCallbackList::handle_t LLCallbackList::doOnIdleOneTime( const callable_t& func ) { -public: - OnIdleCallbackOneTime(nullary_func_t callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime* self = reinterpret_cast(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } -private: - nullary_func_t mCallable; -}; + // connect_extended() passes the connection to the callback + return mCallbackList.connect_extended( + [func](const handle_t& handle) + { + handle.disconnect(); + func(); + }); +} -void doOnIdleOneTime(nullary_func_t callable) +LLCallbackList::handle_t LLCallbackList::doOnIdleRepeating( const bool_func_t& func ) { - OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); + return mCallbackList.connect_extended( + [func](const handle_t& handle) + { + if (func()) + { + handle.disconnect(); + } + }); } -// Shim class to allow generic boost functions to be run as -// recurring idle callbacks. Callable should return true when done, -// false to continue getting called. -class OnIdleCallbackRepeating -{ -public: - OnIdleCallbackRepeating(bool_func_t callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating* self = reinterpret_cast(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } -private: - bool_func_t mCallable; -}; +/***************************************************************************** +* LLLater +*****************************************************************************/ +LLLater::LLLater() {} -void doOnIdleRepeating(bool_func_t callable) +// Call a given callable once at specified timestamp. +LLLater::handle_t LLLater::doAtTime(nullary_func_t callable, LLDate::timestamp time) { - OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); + bool first{ mQueue.empty() }; + // Pick token FIRST to store a self-reference in mQueue's managed node as + // well as in mHandles. Pre-increment to distinguish 0 from any live + // handle_t. + token_t token{ ++mToken }; + auto handle{ mQueue.emplace(callable, time, token) }; + mHandles.emplace(token, handle); + if (first) + { + // If this is our first entry, register for regular callbacks. + mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); }); + } + return handle_t{ token }; } -class NullaryFuncEventTimer: public LLEventTimer +// Call a given callable once after specified interval. +LLLater::handle_t LLLater::doAfterInterval(nullary_func_t callable, F32 seconds) { -public: - NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } + // Passing 0 is a slightly more expensive way of calling + // LLCallbackList::doOnIdleOneTime(). Are we sure the caller is correct? + // (If there's a valid use case, remove the llassert() and carry on.) + llassert(seconds > 0); + return doAtTime(callable, LLDate::now().secondsSinceEpoch() + seconds); +} -private: - BOOL tick() - { - mCallable(); - return TRUE; - } +// For doPeriodically(), we need a struct rather than a lambda because a +// struct, unlike a lambda, has access to 'this'. +struct Periodic +{ + LLLater* mLater; + bool_func_t mCallable; + LLDate::timestamp mNext; + F32 mSeconds; - nullary_func_t mCallable; + void operator()() + { + if (! mCallable()) + { + // Returning false means please schedule another call. + // Don't call doAfterInterval(), which rereads LLDate::now(), + // since that would defer by however long it took us to wake + // up and notice plus however long callable() took to run. + mNext += mSeconds; + mLater->doAtTime(*this, mNext); + } + } }; -// Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds) +// Call a given callable every specified number of seconds, until it returns true. +LLLater::handle_t LLLater::doPeriodically(bool_func_t callable, F32 seconds) { - new NullaryFuncEventTimer(callable, seconds); + // Passing seconds <= 0 will produce an infinite loop. + llassert(seconds > 0); + auto next{ LLDate::now().secondsSinceEpoch() + seconds }; + return doAtTime(Periodic{ this, callable, next, seconds }, next); } -class BoolFuncEventTimer: public LLEventTimer +bool LLLater::isRunning(handle_t timer) { -public: - BoolFuncEventTimer(bool_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } -private: - BOOL tick() - { - return mCallable(); - } + // A default-constructed timer isn't running. + // A timer we don't find in mHandles has fired or been canceled. + return timer && mHandles.find(timer.token) != mHandles.end(); +} - bool_func_t mCallable; -}; +// Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically() +bool LLLater::cancel(handle_t& timer) +{ + // For exception safety, capture and clear timer before canceling. + // Once we've canceled this handle, don't retain the live handle. + const handle_t ctimer{ timer }; + timer = handle_t(); + return cancel(ctimer); +} -// Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds) +bool LLLater::cancel(const handle_t& timer) +{ + if (! timer) + { + return false; + } + + // fibonacci_heap documentation does not address the question of what + // happens if you call erase() twice with the same handle. Is it a no-op? + // Does it invalidate the heap? Is it UB? + + // Nor do we find any documented way to ask whether a given handle still + // tracks a valid heap node. That's why we capture all returned handles in + // mHandles and validate against that collection. What about the pop() + // call in tick()? How to map from the top() value back to the + // corresponding handle_t? That's why we store func_at::mToken. + + // fibonacci_heap provides a pair of begin()/end() methods to iterate over + // all nodes (NOT in heap order), plus a function to convert from such + // iterators to handles. Without mHandles, that would be our only chance + // to validate. + auto found{ mHandles.find(timer.token) }; + if (found == mHandles.end()) + { + // we don't recognize this handle -- maybe the timer has already + // fired, maybe it was previously canceled. + return false; + } + + // erase from mQueue the handle_t referenced by timer.token + mQueue.erase(found->second); + // before erasing timer.token from mHandles + mHandles.erase(found); + if (mQueue.empty()) + { + // If that was the last active timer, unregister for callbacks. + //LLCallbackList::instance().deleteFunction(mLive); + // Since we're in the source file that knows the true identity of an + // LLCallbackList::handle_t, we don't even need to call instance(). + mLive.disconnect(); + } + return true; +} + +bool LLLater::tick() { - new BoolFuncEventTimer(callable, seconds); + // Fetch current time only on entry, even though running some mQueue task + // may take long enough that the next one after would become ready. We're + // sharing this thread with everything else, and there's a risk we might + // starve it if we have a sequence of tasks that take nontrivial time. + auto now{ LLDate::now().secondsSinceEpoch() }; + auto cutoff{ now + TIMESLICE }; + while (! mQueue.empty()) + { + auto& top{ mQueue.top() }; + if (top.mTime > now) + { + // we've hit an entry that's still in the future: + // done with this tick(), but schedule another call + return false; + } + if (LLDate::now().secondsSinceEpoch() > cutoff) + { + // we still have ready tasks, but we've already eaten too much + // time this tick() -- defer until next tick() -- call again + return false; + } + + // Found a ready task. Hate to copy stuff, but -- what if the task + // indirectly ends up trying to cancel a handle referencing its own + // node in mQueue? If the task has any state, that would be Bad. Copy + // the node before running it. + auto current{ top }; + // remove the mHandles entry referencing this task + mHandles.erase(current.mToken); + // before removing the mQueue task entry itself + mQueue.pop(); + // okay, NOW run + current.mFunc(); + } + // queue is empty: stop callbacks + return true; } diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 89716cd74c..522a9b838b 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -27,53 +27,237 @@ #ifndef LL_LLCALLBACKLIST_H #define LL_LLCALLBACKLIST_H +#include "lldate.h" +#include "llsingleton.h" #include "llstl.h" -#include -#include +#include +#include +#include +#include +#include -class LLCallbackList +/***************************************************************************** +* LLCallbackList: callbacks every idle tick (every callFunctions() call) +*****************************************************************************/ +class LLCallbackList: public LLSingleton { + LLSINGLETON(LLCallbackList); public: typedef void (*callback_t)(void*); - typedef std::pair< callback_t,void* > callback_pair_t; - // NOTE: It is confirmed that we DEPEND on the order provided by using a list :( - // - typedef std::list< callback_pair_t > callback_list_t; - - LLCallbackList(); + typedef boost::signals2::signal callback_list_t; + typedef callback_list_t::slot_type callable_t; + typedef boost::signals2::connection handle_t; + typedef boost::signals2::scoped_connection temp_handle_t; + typedef std::function bool_func_t; + ~LLCallbackList(); - void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) + handle_t addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) + handle_t addFunction( const callable_t& func ); bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found - void callFunctions(); // calls all functions + void deleteFunction( const handle_t& handle ); + void callFunctions(); // calls all functions void deleteAllFunctions(); + handle_t doOnIdleOneTime( const callable_t& func ); + handle_t doOnIdleRepeating( const bool_func_t& func ); + bool isRunning(const handle_t& handle) const { return handle.connected(); }; + static void test(); protected: - - inline callback_list_t::iterator find(callback_t func, void *data); - callback_list_t mCallbackList; + + // "Additional specializations for std::pair and the standard container + // types, as well as utility functions to compose hashes are available in + // boost::hash." + // https://en.cppreference.com/w/cpp/utility/hash + typedef std::pair< callback_t,void* > callback_pair_t; + typedef std::unordered_map> lookup_table; + lookup_table mLookup; }; -typedef boost::function nullary_func_t; -typedef boost::function bool_func_t; +/*-------------------- legacy names in global namespace --------------------*/ +#define gIdleCallbacks (LLCallbackList::instance()) + +using nullary_func_t = LLCallbackList::callable_t; +using bool_func_t = LLCallbackList::bool_func_t; // Call a given callable once in idle loop. -void doOnIdleOneTime(nullary_func_t callable); +inline +LLCallbackList::handle_t doOnIdleOneTime(nullary_func_t callable) +{ + return gIdleCallbacks.doOnIdleOneTime(callable); +} // Repeatedly call a callable in idle loop until it returns true. -void doOnIdleRepeating(bool_func_t callable); +inline +LLCallbackList::handle_t doOnIdleRepeating(bool_func_t callable) +{ + return gIdleCallbacks.doOnIdleRepeating(callable); +} + +/***************************************************************************** +* LLLater: callbacks at some future time +*****************************************************************************/ +class LLLater: public LLSingleton +{ + LLSINGLETON(LLLater); + + using token_t = U32; + + // Define a struct for our priority queue entries, instead of using + // a tuple, because we need to define the comparison operator. + struct func_at + { + nullary_func_t mFunc; + LLDate::timestamp mTime; + token_t mToken; + + func_at(const nullary_func_t& func, LLDate::timestamp tm, token_t token): + mFunc(func), + mTime(tm), + mToken(token) + {} + + friend bool operator<(const func_at& lhs, const func_at& rhs) + { + // use greater-than because we want fibonacci_heap to select the + // EARLIEST time as the top() + return lhs.mTime > rhs.mTime; + } + }; + + // Accept default stable: when two funcs have the same timestamp, + // we don't care in what order they're called. + // Specify constant_time_size: we don't need to optimize the size() + // method, iow we don't need to store and maintain a count of entries. + typedef boost::heap::fibonacci_heap> + queue_t; + +public: + // If tasks that come ready during a given tick() take longer than this, + // defer any subsequent ready tasks to a future tick() call. + static constexpr F32 TIMESLICE{ 0.005f }; + class handle_t + { + private: + friend class LLLater; + token_t token; + public: + handle_t(token_t token=0): token(token) {} + bool operator==(const handle_t& rhs) const { return this->token == rhs.token; } + explicit operator bool() const { return bool(token); } + bool operator!() const { return ! bool(*this); } + }; + + // Call a given callable once at specified timestamp. + handle_t doAtTime(nullary_func_t callable, LLDate::timestamp time); + + // Call a given callable once after specified interval. + handle_t doAfterInterval(nullary_func_t callable, F32 seconds); + + // Call a given callable every specified number of seconds, until it returns true. + handle_t doPeriodically(bool_func_t callable, F32 seconds); + + // test whether specified handle is still live + bool isRunning(handle_t timer); + + // Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically(). + // Return true iff the handle corresponds to a live timer. + bool cancel(const handle_t& timer); + // If we're canceling a non-const handle_t, also clear it so we need not + // cancel again. + bool cancel(handle_t& timer); + + // Store a handle_t returned by doAtTime(), doAfterInterval() or + // doPeriodically() in a temp_handle_t to cancel() automatically on + // destruction of the temp_handle_t. + class temp_handle_t + { + public: + temp_handle_t() {} + temp_handle_t(const handle_t& hdl): mHandle(hdl) {} + temp_handle_t(const temp_handle_t&) = delete; + temp_handle_t(temp_handle_t&&) = default; + temp_handle_t& operator=(const handle_t& hdl) + { + // initializing a new temp_handle_t, then swapping it into *this, + // takes care of destroying any previous mHandle + temp_handle_t replacement(hdl); + swap(replacement); + return *this; + } + temp_handle_t& operator=(const temp_handle_t&) = delete; + temp_handle_t& operator=(temp_handle_t&&) = default; + ~temp_handle_t() + { + cancel(); + } + + // temp_handle_t should be usable wherever handle_t is + operator handle_t() const { return mHandle; } + // If we're dealing with a non-const temp_handle_t, pass a reference + // to our handle_t member (e.g. to LLLater::cancel()). + operator handle_t&() { return mHandle; } + + // For those in the know, provide a cancel() method of our own that + // avoids LLLater::instance() lookup when mHandle isn't live. + bool cancel() + { + if (! mHandle) + { + return false; + } + else + { + return LLLater::instance().cancel(mHandle); + } + } + + void swap(temp_handle_t& other) noexcept + { + std::swap(this->mHandle, other.mHandle); + } + + private: + handle_t mHandle; + }; + +private: + bool tick(); + + // NOTE: We don't lock our data members because it doesn't make sense to + // register cross-thread callbacks. If we start wanting to use them on + // threads other than the main thread, it would make more sense to make + // our data members thread_local than to lock them. + + // the heap aka priority queue + queue_t mQueue; + // handles we've returned that haven't yet canceled + std::unordered_map mHandles; + token_t mToken{ 0 }; + // While mQueue is non-empty, register for regular callbacks. + LLCallbackList::temp_handle_t mLive; +}; + +/*-------------------- legacy names in global namespace --------------------*/ // Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds); +inline +LLLater::handle_t doAfterInterval(nullary_func_t callable, F32 seconds) +{ + return LLLater::instance().doAfterInterval(callable, seconds); +} // Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds); - -extern LLCallbackList gIdleCallbacks; +inline +LLLater::handle_t doPeriodically(bool_func_t callable, F32 seconds) +{ + return LLLater::instance().doPeriodically(callable, seconds); +} #endif diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 2ddcf40895..6c23444820 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -41,9 +41,9 @@ #include "llstring.h" #include "llfasttimer.h" -static const F64 DATE_EPOCH = 0.0; +static const LLDate::timestamp DATE_EPOCH = 0.0; -static const F64 LL_APR_USEC_PER_SEC = 1000000.0; +static const LLDate::timestamp LL_APR_USEC_PER_SEC = 1000000.0; // should be APR_USEC_PER_SEC, but that relies on INT64_C which // isn't defined in glib under our build set up for some reason @@ -233,13 +233,13 @@ bool LLDate::fromStream(std::istream& s) return false; } - F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC; + timestamp seconds_since_epoch = time / LL_APR_USEC_PER_SEC; // check for fractional c = s.peek(); if(c == '.') { - F64 fractional = 0.0; + timestamp fractional = 0.0; s >> fractional; seconds_since_epoch += fractional; } @@ -299,12 +299,12 @@ bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec return true; } -F64 LLDate::secondsSinceEpoch() const +LLDate::timestamp LLDate::secondsSinceEpoch() const { return mSecondsSinceEpoch; } -void LLDate::secondsSinceEpoch(F64 seconds) +void LLDate::secondsSinceEpoch(timestamp seconds) { mSecondsSinceEpoch = seconds; } diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index be2cd2d051..c3d0cb97f3 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -44,6 +44,8 @@ class LL_COMMON_API LLDate { public: + using timestamp = F64; + /** * @brief Construct a date equal to epoch. */ @@ -103,14 +105,14 @@ public: * * @return The number of seconds since epoch UTC. */ - F64 secondsSinceEpoch() const; + timestamp secondsSinceEpoch() const; /** * @brief Set the date in seconds since epoch. * * @param seconds The number of seconds since epoch UTC. */ - void secondsSinceEpoch(F64 seconds); + void secondsSinceEpoch(timestamp seconds); /** * @brief Create an LLDate object set to the current time. @@ -147,7 +149,7 @@ public: private: - F64 mSecondsSinceEpoch; + timestamp mSecondsSinceEpoch; }; // Helper function to stream out a date diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h deleted file mode 100644 index 31dd207008..0000000000 --- a/indra/llcommon/llerrorlegacy.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file llerrorlegacy.h - * @date January 2007 - * @brief old things from the older error system - * - * $LicenseInfo:firstyear=2007&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_LLERRORLEGACY_H -#define LL_LLERRORLEGACY_H - - -#endif // LL_LLERRORLEGACY_H diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index 14c9c51830..e72ae7ad33 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -73,115 +73,52 @@ bool LLEventMatching::post(const LLSD& event) } /***************************************************************************** -* LLEventTimeoutBase +* LLEventTimeout *****************************************************************************/ -LLEventTimeoutBase::LLEventTimeoutBase(): +LLEventTimeout::LLEventTimeout(): LLEventFilter("timeout") { } -LLEventTimeoutBase::LLEventTimeoutBase(LLEventPump& source): +LLEventTimeout::LLEventTimeout(LLEventPump& source): LLEventFilter(source, "timeout") { } -void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action) +void LLEventTimeout::actionAfter(F32 seconds, const Action& action) { - setCountdown(seconds); - mAction = action; - if (! mMainloop.connected()) - { - LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - mMainloop = mainloop.listen(getName(), [this](const LLSD& event){ return tick(event); }); - } + mTimer = LLLater::instance().doAfterInterval(action, seconds); } -class ErrorAfter -{ -public: - ErrorAfter(const std::string& message): mMessage(message) {} - - void operator()() - { - LL_ERRS("LLEventTimeout") << mMessage << LL_ENDL; - } - -private: - std::string mMessage; -}; - -void LLEventTimeoutBase::errorAfter(F32 seconds, const std::string& message) +void LLEventTimeout::errorAfter(F32 seconds, const std::string& message) { - actionAfter(seconds, ErrorAfter(message)); + actionAfter( + seconds, + [message=message] + { + LL_ERRS("LLEventTimeout") << message << LL_ENDL; + }); } -class EventAfter +void LLEventTimeout::eventAfter(F32 seconds, const LLSD& event) { -public: - EventAfter(LLEventPump& pump, const LLSD& event): - mPump(pump), - mEvent(event) - {} - - void operator()() - { - mPump.post(mEvent); - } - -private: - LLEventPump& mPump; - LLSD mEvent; -}; - -void LLEventTimeoutBase::eventAfter(F32 seconds, const LLSD& event) -{ - actionAfter(seconds, EventAfter(*this, event)); + actionAfter(seconds, [this, event]{ post(event); }); } -bool LLEventTimeoutBase::post(const LLSD& event) +bool LLEventTimeout::post(const LLSD& event) { cancel(); return LLEventStream::post(event); } -void LLEventTimeoutBase::cancel() -{ - mMainloop.disconnect(); -} - -bool LLEventTimeoutBase::tick(const LLSD&) -{ - if (countdownElapsed()) - { - cancel(); - mAction(); - } - return false; // show event to other listeners -} - -bool LLEventTimeoutBase::running() const -{ - return mMainloop.connected(); -} - -/***************************************************************************** -* LLEventTimeout -*****************************************************************************/ -LLEventTimeout::LLEventTimeout() {} - -LLEventTimeout::LLEventTimeout(LLEventPump& source): - LLEventTimeoutBase(source) +void LLEventTimeout::cancel() { + mTimer.cancel(); } -void LLEventTimeout::setCountdown(F32 seconds) +bool LLEventTimeout::running() const { - mTimer.setTimerExpirySec(seconds); -} - -bool LLEventTimeout::countdownElapsed() const -{ - return mTimer.hasExpired(); + return LLLater::instance().isRunning(mTimer); } /***************************************************************************** @@ -224,21 +161,21 @@ void LLEventBatch::setSize(std::size_t size) } /***************************************************************************** -* LLEventThrottleBase +* LLEventThrottle *****************************************************************************/ -LLEventThrottleBase::LLEventThrottleBase(F32 interval): +LLEventThrottle::LLEventThrottle(F32 interval): LLEventFilter("throttle"), mInterval(interval), mPosts(0) {} -LLEventThrottleBase::LLEventThrottleBase(LLEventPump& source, F32 interval): +LLEventThrottle::LLEventThrottle(LLEventPump& source, F32 interval): LLEventFilter(source, "throttle"), mInterval(interval), mPosts(0) {} -void LLEventThrottleBase::flush() +void LLEventThrottle::flush() { // flush() is a no-op unless there's something pending. // Don't test mPending because there's no requirement that the consumer @@ -259,12 +196,12 @@ void LLEventThrottleBase::flush() } } -LLSD LLEventThrottleBase::pending() const +LLSD LLEventThrottle::pending() const { return mPending; } -bool LLEventThrottleBase::post(const LLSD& event) +bool LLEventThrottle::post(const LLSD& event) { // Always capture most recent post() event data. If caller wants to // aggregate multiple events, let them retrieve pending() and modify @@ -289,13 +226,13 @@ bool LLEventThrottleBase::post(const LLSD& event) // timeRemaining tells us how much longer it will be until // mInterval seconds since the last flush() call. At that time, // flush() deferred events. - alarmActionAfter(timeRemaining, [this](){ flush(); }); + alarmActionAfter(timeRemaining, [this]{ flush(); }); } } return false; } -void LLEventThrottleBase::setInterval(F32 interval) +void LLEventThrottle::setInterval(F32 interval) { F32 oldInterval = mInterval; mInterval = interval; @@ -333,35 +270,24 @@ void LLEventThrottleBase::setInterval(F32 interval) } } -F32 LLEventThrottleBase::getDelay() const +F32 LLEventThrottle::getDelay() const { return timerGetRemaining(); } -/***************************************************************************** -* LLEventThrottle implementation -*****************************************************************************/ -LLEventThrottle::LLEventThrottle(F32 interval): - LLEventThrottleBase(interval) -{} - -LLEventThrottle::LLEventThrottle(LLEventPump& source, F32 interval): - LLEventThrottleBase(source, interval) -{} - -void LLEventThrottle::alarmActionAfter(F32 interval, const LLEventTimeoutBase::Action& action) +void LLEventThrottle::alarmActionAfter(F32 interval, const LLEventTimeout::Action& action) { - mAlarm.actionAfter(interval, action); + mAlarm = LLLater::instance().doAfterInterval(action, interval); } bool LLEventThrottle::alarmRunning() const { - return mAlarm.running(); + return LLLater::instance().isRunning(mAlarm); } void LLEventThrottle::alarmCancel() { - return mAlarm.cancel(); + LLLater::instance().cancel(mAlarm); } void LLEventThrottle::timerSet(F32 interval) diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 88dc5a3015..1deb6f0f4c 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -29,13 +29,13 @@ #if ! defined(LL_LLEVENTFILTER_H) #define LL_LLEVENTFILTER_H +#include "llcallbacklist.h" #include "llevents.h" -#include "stdtypes.h" -#include "lltimer.h" #include "llsdutil.h" -#include +#include "lltimer.h" +#include "stdtypes.h" +#include -class LLEventTimer; class LLDate; /** @@ -78,22 +78,27 @@ private: /** * Wait for an event to be posted. If no such event arrives within a specified - * time, take a specified action. See LLEventTimeout for production - * implementation. - * - * @NOTE This is an abstract base class so that, for testing, we can use an - * alternate "timer" that doesn't actually consume real time. + * time, take a specified action. + * + * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) + * constructor to ensure that the upstream event pump is not an LLEventMaildrop + * or any other kind of store and forward pump which may have events outstanding. + * Using this constructor will cause the upstream event pump to fire any pending + * events and could result in the invocation of a virtual method before the timeout + * has been fully constructed. The timeout should instead be constructed separately + * from the event pump and attached using the listen method. + * See llcoro::suspendUntilEventOnWithTimeout() for an example. */ -class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter +class LL_COMMON_API LLEventTimeout: public LLEventFilter { public: /// construct standalone - LLEventTimeoutBase(); + LLEventTimeout(); /// construct and connect - LLEventTimeoutBase(LLEventPump& source); + LLEventTimeout(LLEventPump& source); /// Callable, can be constructed with boost::bind() - typedef boost::function Action; + typedef std::function Action; /** * Start countdown timer for the specified number of @a seconds. Forward @@ -120,8 +125,8 @@ public: * @endcode * * @NOTE - * The implementation relies on frequent events on the LLEventPump named - * "mainloop". + * The implementation relies on frequent calls to + * gIdleCallbacks.callFunctions(). */ void actionAfter(F32 seconds, const Action& action); @@ -134,7 +139,7 @@ public: * Instantiate an LLEventTimeout listening to that API and call * errorAfter() on each async request with a timeout comfortably longer * than the API's time guarantee (much longer than the anticipated - * "mainloop" granularity). + * gIdleCallbacks.callFunctions() granularity). * * Then if the async API breaks its promise, the program terminates with * the specified LL_ERRS @a message. The client of the async API can @@ -184,42 +189,9 @@ public: /// Is this timer currently running? bool running() const; -protected: - virtual void setCountdown(F32 seconds) = 0; - virtual bool countdownElapsed() const = 0; - private: - bool tick(const LLSD&); - - LLTempBoundListener mMainloop; - Action mAction; -}; - -/** - * Production implementation of LLEventTimoutBase. - * - * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) - * constructor to ensure that the upstream event pump is not an LLEventMaildrop - * or any other kind of store and forward pump which may have events outstanding. - * Using this constructor will cause the upstream event pump to fire any pending - * events and could result in the invocation of a virtual method before the timeout - * has been fully constructed. The timeout should instead be connected upstream - * from the event pump and attached using the listen method. - * See llcoro::suspendUntilEventOnWithTimeout() for an example. - */ - -class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase -{ -public: - LLEventTimeout(); - LLEventTimeout(LLEventPump& source); - -protected: - virtual void setCountdown(F32 seconds); - virtual bool countdownElapsed() const; - -private: - LLTimer mTimer; + // Use a temp_handle_t so it's canceled on destruction. + LLLater::temp_handle_t mTimer; }; /** @@ -251,7 +223,7 @@ private: }; /** - * LLEventThrottleBase: construct with a time interval. Regardless of how + * LLEventThrottle: construct with a time interval. Regardless of how * frequently you call post(), LLEventThrottle will pass on an event to * its listeners no more often than once per specified interval. * @@ -284,13 +256,13 @@ private: * alternate "timer" that doesn't actually consume real time. See * LLEventThrottle. */ -class LL_COMMON_API LLEventThrottleBase: public LLEventFilter +class LL_COMMON_API LLEventThrottle: public LLEventFilter { public: // pass time interval - LLEventThrottleBase(F32 interval); + LLEventThrottle(F32 interval); // construct and connect - LLEventThrottleBase(LLEventPump& source, F32 interval); + LLEventThrottle(LLEventPump& source, F32 interval); // force out any deferred events void flush(); @@ -311,45 +283,24 @@ public: // time until next event would be passed through, 0.0 if now F32 getDelay() const; -protected: - // Implement these time-related methods for a valid LLEventThrottleBase - // subclass (see LLEventThrottle). For testing, we use a subclass that - // doesn't involve actual elapsed time. - virtual void alarmActionAfter(F32 interval, const LLEventTimeoutBase::Action& action) = 0; - virtual bool alarmRunning() const = 0; - virtual void alarmCancel() = 0; - virtual void timerSet(F32 interval) = 0; - virtual F32 timerGetRemaining() const = 0; - private: - // remember throttle interval - F32 mInterval; - // count post() calls since last flush() - std::size_t mPosts; + void alarmActionAfter(F32 interval, const LLEventTimeout::Action& action); + bool alarmRunning() const; + void alarmCancel(); + void timerSet(F32 interval); + F32 timerGetRemaining() const; + // pending event data from most recent deferred event LLSD mPending; -}; - -/** - * Production implementation of LLEventThrottle. - */ -class LLEventThrottle: public LLEventThrottleBase -{ -public: - LLEventThrottle(F32 interval); - LLEventThrottle(LLEventPump& source, F32 interval); - -private: - virtual void alarmActionAfter(F32 interval, const LLEventTimeoutBase::Action& action) /*override*/; - virtual bool alarmRunning() const /*override*/; - virtual void alarmCancel() /*override*/; - virtual void timerSet(F32 interval) /*override*/; - virtual F32 timerGetRemaining() const /*override*/; - - // use this to arrange a deferred flush() call - LLEventTimeout mAlarm; // use this to track whether we're within mInterval of last flush() LLTimer mTimer; + // count post() calls since last flush() + std::size_t mPosts; + // remember throttle interval + F32 mInterval; + + // use this to arrange a deferred flush() call + LLLater::handle_t mAlarm; }; /** diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index f575a7b6bf..b163ad375c 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -25,49 +25,34 @@ */ #include "linden_common.h" - #include "lleventtimer.h" -#include "u64.h" - - ////////////////////////////////////////////////////////////////////////////// // // LLEventTimer Implementation // ////////////////////////////////////////////////////////////////////////////// -LLEventTimer::LLEventTimer(F32 period) -: mEventTimer() +LLEventTimer::LLEventTimer(F32 period): + mPeriod(period) { - mPeriod = period; -} - -LLEventTimer::LLEventTimer(const LLDate& time) -: mEventTimer() -{ - mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); + start(); } +LLEventTimer::LLEventTimer(const LLDate& time): + LLEventTimer(F32(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch())) +{} LLEventTimer::~LLEventTimer() { } -//static -void LLEventTimer::updateClass() +void LLEventTimer::start() { - for (auto& timer : instance_snapshot()) - { - F32 et = timer.mEventTimer.getElapsedTimeF32(); - if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { - timer.mEventTimer.reset(); - if ( timer.tick() ) - { - delete &timer; - } - } - } + mTimer = LLLater::instance().doPeriodically([this]{ return tick(); }, mPeriod); } - +void LLEventTimer::stop() +{ + LLLater::instance().cancel(mTimer); +} diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index b5d40a0622..34ff157e22 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -27,13 +27,12 @@ #ifndef LL_EVENTTIMER_H #define LL_EVENTTIMER_H -#include "stdtypes.h" +#include "llcallbacklist.h" #include "lldate.h" -#include "llinstancetracker.h" -#include "lltimer.h" +#include "stdtypes.h" // class for scheduling a function to be called at a given frequency (approximate, inprecise) -class LL_COMMON_API LLEventTimer : public LLInstanceTracker +class LL_COMMON_API LLEventTimer { public: @@ -41,14 +40,15 @@ public: LLEventTimer(const LLDate& time); virtual ~LLEventTimer(); - //function to be called at the supplied frequency - // Normally return FALSE; TRUE will delete the timer after the function returns. - virtual BOOL tick() = 0; + void start(); + void stop(); - static void updateClass(); + //function to be called at the supplied frequency + // Normally return false; true will delete the timer after the function returns. + virtual bool tick() = 0; protected: - LLTimer mEventTimer; + LLLater::temp_handle_t mTimer; F32 mPeriod; }; diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp index ea485c2d86..692a21c1f1 100644 --- a/indra/llcommon/lllivefile.cpp +++ b/indra/llcommon/lllivefile.cpp @@ -170,7 +170,7 @@ namespace : LLEventTimer(refresh), mLiveFile(f) { } - BOOL tick() + bool tick() override { mLiveFile.checkAndReload(); return FALSE; diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index fa2cb03e95..38d6d0076e 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -51,6 +51,7 @@ // as we've carefully put all functionality except actual LLTimer calls into // LLEventTimeoutBase, that should suffice. We're not not not trying to test // LLTimer here. +#if 0 // time testing needs reworking class TestEventTimeout: public LLEventTimeoutBase { public: @@ -151,6 +152,7 @@ public: F32 mAlarmRemaining, mTimerRemaining; LLEventTimeoutBase::Action mAlarmAction; }; +#endif // time testing needs reworking /***************************************************************************** * TUT @@ -220,6 +222,8 @@ namespace tut void filter_object::test<2>() { set_test_name("LLEventTimeout::actionAfter()"); + skip("time testing needs reworking"); +#if 0 // time testing needs reworking LLEventPump& driver(pumps.obtain("driver")); TestEventTimeout filter(driver); listener0.reset(0); @@ -285,12 +289,15 @@ namespace tut filter.forceTimeout(); mainloop.post(17); check_listener("no timeout 6", listener1, LLSD(0)); +#endif // time testing needs reworking } template<> template<> void filter_object::test<3>() { set_test_name("LLEventTimeout::eventAfter()"); + skip("time testing needs reworking"); +#if 0 // time testing needs reworking LLEventPump& driver(pumps.obtain("driver")); TestEventTimeout filter(driver); listener0.reset(0); @@ -322,12 +329,15 @@ namespace tut filter.forceTimeout(); mainloop.post(17); check_listener("no timeout 3", listener0, LLSD(0)); +#endif // time testing needs reworking } template<> template<> void filter_object::test<4>() { set_test_name("LLEventTimeout::errorAfter()"); + skip("time testing needs reworking"); +#if 0 // time testing needs reworking WrapLLErrs capture; LLEventPump& driver(pumps.obtain("driver")); TestEventTimeout filter(driver); @@ -362,12 +372,15 @@ namespace tut filter.forceTimeout(); mainloop.post(17); check_listener("no timeout 3", listener0, LLSD(0)); +#endif // time testing needs reworking } template<> template<> void filter_object::test<5>() { set_test_name("LLEventThrottle"); + skip("time testing needs reworking"); +#if 0 // time testing needs reworking TestEventThrottle throttle(3); Concat cat; throttle.listen("concat", boost::ref(cat)); @@ -403,6 +416,7 @@ namespace tut throttle.advance(5); throttle.post(";17"); ensure_equals("17", cat.result, "136;12;17"); // "17" delivered +#endif // time testing needs reworking } template diff --git a/indra/llcommon/tests/llmainthreadtask_test.cpp b/indra/llcommon/tests/llmainthreadtask_test.cpp index 69b11ccafb..4a15e30a30 100644 --- a/indra/llcommon/tests/llmainthreadtask_test.cpp +++ b/indra/llcommon/tests/llmainthreadtask_test.cpp @@ -20,8 +20,8 @@ // other Linden headers #include "../test/lltut.h" #include "../test/sync.h" +#include "llcallbacklist.h" #include "llthread.h" // on_main_thread() -#include "lleventtimer.h" #include "lockstatic.h" /***************************************************************************** @@ -108,7 +108,7 @@ namespace tut lk.unlock(); // run the task -- should unblock thread, which will immediately block // on mSync - LLEventTimer::updateClass(); + LLCallbackList::instance().callFunctions(); // 'lk', having unlocked, can no longer be used to access; relock with // a new LockStatic instance ensure("should now have run", LockStatic()->ran); diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 39793316f4..4a5b220008 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -31,11 +31,11 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) : LLEventTimer(period), mCallback(cb), mCurrentTickCount(0), - mIsFlashingInProgress(false), - mIsCurrentlyHighlighted(false), - mUnset(false) + mIsFlashingInProgress(false), + mIsCurrentlyHighlighted(false), + mUnset(false) { - mEventTimer.stop(); + stop(); // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. // Due to Timer is implemented as derived class from EventTimer it is impossible to change period @@ -53,7 +53,7 @@ void LLFlashTimer::unset() mCallback = NULL; } -BOOL LLFlashTimer::tick() +bool LLFlashTimer::tick() { mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; @@ -74,12 +74,12 @@ void LLFlashTimer::startFlashing() { mIsFlashingInProgress = true; mIsCurrentlyHighlighted = true; - mEventTimer.start(); + start(); } void LLFlashTimer::stopFlashing() { - mEventTimer.stop(); + stop(); mIsFlashingInProgress = false; mIsCurrentlyHighlighted = false; mCurrentTickCount = 0; diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index db8d49f009..4a2088734d 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -46,7 +46,7 @@ public: LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); ~LLFlashTimer() {}; - /*virtual*/ BOOL tick(); + bool tick() override; void startFlashing(); void stopFlashing(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index c84657cf7a..7e84ad3b2a 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -123,8 +123,7 @@ public: stop(); } - /*virtual*/ - BOOL tick() + bool tick() override { if(mEventTimer.hasExpired()) { @@ -332,7 +331,7 @@ public: // virtual // Will be deleted after returning true - only safe to do this if all callbacks have fired. - BOOL tick() + bool tick() override { // mPendingRequests will be zero if all requests have been // responded to. mWaitTimes.empty() will be true if we have diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index 237d58b4de..2d39b5efed 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -42,7 +42,7 @@ public: ~LLDoNotDisturbNotificationStorageTimer(); public: - BOOL tick(); + bool tick() override; }; class LLDoNotDisturbNotificationStorage : public LLParamSingleton, public LLNotificationStorage diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index 060773f93e..8d91187a33 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -89,7 +89,7 @@ public: BOOL postBuild(); virtual void onOpen(const LLSD& key); - virtual BOOL tick(); + bool tick() override; private: void checkEnableStart(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index a3e173398f..34dc263519 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1960,7 +1960,7 @@ public: protected: - BOOL tick() + bool tick() override { mCallback(mNewValue); mEventTimer.stop(); diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h index 46416db2c8..d254149e30 100644 --- a/indra/newview/llfloaterregionrestarting.h +++ b/indra/newview/llfloaterregionrestarting.h @@ -43,7 +43,7 @@ private: LLFloaterRegionRestarting(const LLSD& key); virtual ~LLFloaterRegionRestarting(); virtual BOOL postBuild(); - virtual BOOL tick(); + bool tick() override; virtual void refresh(); virtual void draw(); virtual void regionChange(); diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 553d09bec2..6da380c639 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -254,7 +254,7 @@ class LLFadeEventTimer : public LLEventTimer { public: LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); - BOOL tick(); + bool tick() override; LLGUIPreviewLiveFile* mParent; private: BOOL mFadingOut; // fades in then out; this is toggled in between diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index bace97d37a..f0e3e26a86 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -51,7 +51,7 @@ class LLSessionTimeoutTimer : public LLEventTimer public: LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {} virtual ~LLSessionTimeoutTimer() {}; - /* virtual */ BOOL tick(); + bool tick() override; private: LLUUID mSessionId; diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 1fdf9dccbf..8420049b1e 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -121,7 +121,7 @@ class LLLocalBitmapTimer : public LLEventTimer void startTimer(); void stopTimer(); bool isRunning(); - BOOL tick(); + bool tick() override; }; diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index 13b7577e96..53639dfb1d 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -90,7 +90,7 @@ public: void startTimer(); void stopTimer(); bool isRunning(); - BOOL tick(); + bool tick() override; }; class LLLocalGLTFMaterialMgr : public LLSingleton diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 8cd4793106..428e85b976 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -219,13 +219,13 @@ protected: { public: RetryTimer(F32 time, Request::ptr_t); - virtual BOOL tick(); + virtual bool tick() override; private: // back-pointer Request::ptr_t mRequest; }; - - + + protected: typedef std::list request_queue_t; typedef std::set request_set_t; @@ -286,12 +286,12 @@ private: { public: QueueTimer(F32 time, LLMediaDataClient *mdc); - virtual BOOL tick(); + bool tick() override; private: // back-pointer LLPointer mMDC; }; - + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } bool mQueueTimerIsRunning; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 13b52e97c5..aad6ceecb2 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -313,7 +313,7 @@ public: mEventTimer.stop(); } - virtual BOOL tick() // from LLEventTimer + virtual bool tick() override // from LLEventTimer { return FALSE; } @@ -367,7 +367,7 @@ public: } - /*virtual*/ BOOL tick() + bool tick() override { if (!mIsActive) return FALSE; @@ -508,7 +508,7 @@ public: } } - /*virtual*/ BOOL tick() + bool tick() override { update(); return FALSE; diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 74844a80e8..79d03922cc 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -53,7 +53,7 @@ public: virtual ~Updater(){} protected: - BOOL tick() + bool tick() override { mCallback(mMask); // Deletes itseft after execution diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 22c9481687..0242da1605 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -159,7 +159,7 @@ public: * * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). */ - virtual BOOL tick(); + bool tick() override; /** * Clears the callback. diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 223aaad811..d30e028d33 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -43,34 +43,21 @@ LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period) { } -/*virtual*/ -BOOL LLToastLifeTimer::tick() -{ - if (mEventTimer.hasExpired()) - { - mToast->expire(); - } - return FALSE; -} - -void LLToastLifeTimer::stop() -{ - mEventTimer.stop(); -} - -void LLToastLifeTimer::start() +bool LLToastLifeTimer::tick() { - mEventTimer.start(); + mToast->expire(); + return false; } void LLToastLifeTimer::restart() { - mEventTimer.reset(); + // start() discards any previously-running mTimer + start(); } -BOOL LLToastLifeTimer::getStarted() +bool LLToastLifeTimer::getStarted() { - return mEventTimer.getStarted(); + return LLLater::instance.isRunning(mTimer); } void LLToastLifeTimer::setPeriod(F32 period) @@ -78,12 +65,14 @@ void LLToastLifeTimer::setPeriod(F32 period) mPeriod = period; } +/*==========================================================================*| F32 LLToastLifeTimer::getRemainingTimeF32() { F32 et = mEventTimer.getElapsedTimeF32(); if (!getStarted() || et > mPeriod) return 0.0f; return mPeriod - et; } +|*==========================================================================*/ //-------------------------------------------------------------------------- LLToast::Params::Params() diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index ab559f1e6f..49969ab70a 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -53,15 +53,13 @@ public: LLToastLifeTimer(LLToast* toast, F32 period); /*virtual*/ - BOOL tick(); - void stop(); - void start(); + bool tick() override; void restart(); - BOOL getStarted(); + bool getStarted(); void setPeriod(F32 period); - F32 getRemainingTimeF32(); +// F32 getRemainingTimeF32(); - LLTimer& getEventTimer() { return mEventTimer;} +// LLTimer& getEventTimer() { return mEventTimer;} private : LLToast* mToast; }; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ff2753d240..b65305337f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2890,7 +2890,7 @@ public: virtual ~LLPostTeleportNotifiers(); //function to be called at the supplied frequency - virtual BOOL tick(); + bool tick() override; }; LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index e83085dee0..9367c2a629 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -35,7 +35,7 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton Date: Thu, 2 May 2024 23:57:29 -0400 Subject: Introduce LLLater::getRemaining(handle). Some timer use cases need to know not only whether the timer is active, but how much time remains before it (next) fires. Introduce LLLater::mDoneTimes to track, for each handle, the timestamp at which it's expected to fire. We can't just look up the target timestamp in mQueue's func_at entry because there's no documented way to navigate from a handle_type to a node iterator or pointer. Nor can we store it in mHandles because of order dependency: we need the mDoneTimes iterator so we can bind it into the Periodic functor for doPeriodically(), but we need the mQueue handle to store in mHandles. If we could find the mQueue node from the new handle, we could update the func_at entry after emplace() -- but if we could find the mQueue node from a handle, we wouldn't need to store the target timestamp separately anyway. Split LLLater::doAtTime() into internal doAtTime1() and doAtTime2(): the first creates an mDoneTimes entry and returns an iterator, the second finishes creating new mQueue and mHandles entries based on that mDoneTimes entry. This lets doPeriodically()'s Periodic bind the mDoneTimes iterator. Then instead of continually incrementing an internal data member, it increments the mDoneTimes entry to set the next upcoming timestamp. That lets getRemaining() report the next upcoming timestamp rather than only the original one. Add LLEventTimer::isRunning() and getRemaining(), forwarding to its LLLater handle. Fix various LLEventTimer subclass references to mEventTimer.stop(), etc. Fix non-inline LLEventTimer subclass tick() overrides for bool, not BOOL. Remove LLAppViewer::idle() call to LLEventTimer::updateClass(). Since LLApp::stepFrame() already calls LLCallbackList::callFunctions(), assume we've already handled that every tick. --- indra/llcommon/llcallbacklist.cpp | 64 +++++++++++++++++----- indra/llcommon/llcallbacklist.h | 23 ++++++-- indra/llcommon/lleventtimer.cpp | 10 ++++ indra/llcommon/lleventtimer.h | 2 + indra/newview/llappearancemgr.cpp | 19 ++----- indra/newview/llappviewer.cpp | 7 +-- .../newview/lldonotdisturbnotificationstorage.cpp | 4 +- indra/newview/llfloaterlinkreplace.cpp | 10 ++-- indra/newview/llfloaterpreference.cpp | 8 +-- indra/newview/llfloaterregionrestarting.cpp | 4 +- indra/newview/llfloateruipreview.cpp | 6 +- indra/newview/llimview.cpp | 6 +- indra/newview/lllocalbitmaps.cpp | 13 ++--- indra/newview/lllocalbitmaps.h | 1 - indra/newview/lllocalgltfmaterials.cpp | 13 ++--- indra/newview/lllocalgltfmaterials.h | 1 - indra/newview/llmediadataclient.cpp | 14 ++--- indra/newview/llpanelpeople.cpp | 18 +++--- indra/newview/llsetkeybinddialog.cpp | 4 +- indra/newview/llspeakers.cpp | 4 +- indra/newview/lltoast.cpp | 4 +- indra/newview/llviewermessage.cpp | 6 +- indra/newview/llviewerparcelmediaautoplay.cpp | 4 +- 23 files changed, 142 insertions(+), 103 deletions(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 7f7fdc7370..85c73fec8f 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -130,22 +130,40 @@ LLCallbackList::handle_t LLCallbackList::doOnIdleRepeating( const bool_func_t& f *****************************************************************************/ LLLater::LLLater() {} -// Call a given callable once at specified timestamp. -LLLater::handle_t LLLater::doAtTime(nullary_func_t callable, LLDate::timestamp time) +LLLater::DoneMap::iterator LLLater::doAtTime1(LLDate::timestamp time) { - bool first{ mQueue.empty() }; // Pick token FIRST to store a self-reference in mQueue's managed node as // well as in mHandles. Pre-increment to distinguish 0 from any live // handle_t. token_t token{ ++mToken }; - auto handle{ mQueue.emplace(callable, time, token) }; - mHandles.emplace(token, handle); + auto [iter, inserted]{ mDoneTimes.emplace(token, time) }; + llassert(inserted); + return iter; +} + +LLLater::handle_t LLLater::doAtTime2(nullary_func_t callable, DoneMap::iterator iter) +{ + bool first{ mQueue.empty() }; + // DoneMap::iterator references (token, time) pair + auto handle{ mQueue.emplace(callable, iter->first, iter->second) }; + auto hiter{ mHandles.emplace(iter->first, handle).first }; + // When called by Periodic, we're passed an existing DoneMap entry, + // meaning the token already exists, meaning emplace() will tell us it + // found an existing entry rather than creating a new one. In that case, + // it's essential to update the handle. + hiter->second = handle; if (first) { // If this is our first entry, register for regular callbacks. mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); }); } - return handle_t{ token }; + return { iter->first }; +} + +// Call a given callable once at specified timestamp. +LLLater::handle_t LLLater::doAtTime(nullary_func_t callable, LLDate::timestamp time) +{ + return doAtTime2(callable, doAtTime1(time)); } // Call a given callable once after specified interval. @@ -160,11 +178,11 @@ LLLater::handle_t LLLater::doAfterInterval(nullary_func_t callable, F32 seconds) // For doPeriodically(), we need a struct rather than a lambda because a // struct, unlike a lambda, has access to 'this'. -struct Periodic +struct LLLater::Periodic { LLLater* mLater; + DoneMap::iterator mDone; bool_func_t mCallable; - LLDate::timestamp mNext; F32 mSeconds; void operator()() @@ -175,8 +193,9 @@ struct Periodic // Don't call doAfterInterval(), which rereads LLDate::now(), // since that would defer by however long it took us to wake // up and notice plus however long callable() took to run. - mNext += mSeconds; - mLater->doAtTime(*this, mNext); + // Bump our mDoneTimes entry so getRemaining() can track. + mDone->second += mSeconds; + mLater->doAtTime2(*this, mDone); } } }; @@ -186,17 +205,32 @@ LLLater::handle_t LLLater::doPeriodically(bool_func_t callable, F32 seconds) { // Passing seconds <= 0 will produce an infinite loop. llassert(seconds > 0); - auto next{ LLDate::now().secondsSinceEpoch() + seconds }; - return doAtTime(Periodic{ this, callable, next, seconds }, next); + auto iter{ doAtTime1(LLDate::now().secondsSinceEpoch() + seconds) }; + // The whole reason we split doAtTime() into doAtTime1() and doAtTime2() + // is to be able to bind the mDoneTimes entry into Periodic. + return doAtTime2(Periodic{ this, iter, callable, seconds }, iter); } -bool LLLater::isRunning(handle_t timer) +bool LLLater::isRunning(handle_t timer) const { // A default-constructed timer isn't running. // A timer we don't find in mHandles has fired or been canceled. return timer && mHandles.find(timer.token) != mHandles.end(); } +F32 LLLater::getRemaining(handle_t timer) const +{ + auto found{ mDoneTimes.find(timer.token) }; + if (found == mDoneTimes.end()) + { + return 0.f; + } + else + { + return found->second - LLDate::now().secondsSinceEpoch(); + } +} + // Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically() bool LLLater::cancel(handle_t& timer) { @@ -240,6 +274,8 @@ bool LLLater::cancel(const handle_t& timer) mQueue.erase(found->second); // before erasing timer.token from mHandles mHandles.erase(found); + // don't forget to erase mDoneTimes entry + mDoneTimes.erase(timer.token); if (mQueue.empty()) { // If that was the last active timer, unregister for callbacks. @@ -282,6 +318,8 @@ bool LLLater::tick() auto current{ top }; // remove the mHandles entry referencing this task mHandles.erase(current.mToken); + // and the mDoneTimes entry + mDoneTimes.erase(current.mToken); // before removing the mQueue task entry itself mQueue.pop(); // okay, NOW run diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 522a9b838b..17adb7f431 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -114,13 +114,13 @@ class LLLater: public LLSingleton struct func_at { nullary_func_t mFunc; - LLDate::timestamp mTime; token_t mToken; + LLDate::timestamp mTime; - func_at(const nullary_func_t& func, LLDate::timestamp tm, token_t token): + func_at(const nullary_func_t& func, token_t token, LLDate::timestamp tm): mFunc(func), - mTime(tm), - mToken(token) + mToken(token), + mTime(tm) {} friend bool operator<(const func_at& lhs, const func_at& rhs) @@ -165,7 +165,9 @@ public: handle_t doPeriodically(bool_func_t callable, F32 seconds); // test whether specified handle is still live - bool isRunning(handle_t timer); + bool isRunning(handle_t timer) const; + // check remaining time + F32 getRemaining(handle_t timer) const; // Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically(). // Return true iff the handle corresponds to a live timer. @@ -239,10 +241,19 @@ private: // the heap aka priority queue queue_t mQueue; // handles we've returned that haven't yet canceled - std::unordered_map mHandles; + using HandleMap = std::unordered_map; + HandleMap mHandles; + using DoneMap = std::unordered_map; + DoneMap mDoneTimes; token_t mToken{ 0 }; // While mQueue is non-empty, register for regular callbacks. LLCallbackList::temp_handle_t mLive; + + struct Periodic; + + // internal implementation for doAtTime() + DoneMap::iterator doAtTime1(LLDate::timestamp time); + handle_t doAtTime2(nullary_func_t callable, DoneMap::iterator iter); }; /*-------------------- legacy names in global namespace --------------------*/ diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index b163ad375c..0f8d1e636f 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -56,3 +56,13 @@ void LLEventTimer::stop() { LLLater::instance().cancel(mTimer); } + +bool LLEventTimer::isRunning() +{ + return LLLater::instance().isRunning(mTimer); +} + +F32 LLEventTimer::getRemaining() +{ + return LLLater::instance().getRemaining(mTimer); +} diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index 34ff157e22..05d8bc038d 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -42,6 +42,8 @@ public: void start(); void stop(); + bool isRunning(); + F32 getRemaining(); //function to be called at the supplied frequency // Normally return false; true will delete the timer after the function returns. diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 7e84ad3b2a..5b8835add8 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -118,25 +118,19 @@ public: LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) { // restart timer on BOF changed event - LLOutfitObserver::instance().addBOFChangedCallback(boost::bind( - &LLOutfitUnLockTimer::reset, this)); + LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); }); stop(); } bool tick() override { - if(mEventTimer.hasExpired()) - { - LLAppearanceMgr::instance().setOutfitLocked(false); - } - return FALSE; + LLAppearanceMgr::instance().setOutfitLocked(false); + return false; } - void stop() { mEventTimer.stop(); } - void start() { mEventTimer.start(); } - void reset() { mEventTimer.reset(); } - BOOL getStarted() { return mEventTimer.getStarted(); } +// void reset() { mEventTimer.reset(); } + bool getStarted() { return isRunning(); } - LLTimer& getEventTimer() { return mEventTimer;} +// LLTimer& getEventTimer() { return mEventTimer;} }; // support for secondlife:///app/appearance SLapps @@ -1706,7 +1700,6 @@ void LLAppearanceMgr::setOutfitLocked(bool locked) mOutfitLocked = locked; if (locked) { - mUnlockOutfitTimer->reset(); mUnlockOutfitTimer->start(); } else diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d6a4c41497..0200ea6ad7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4586,7 +4586,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); /////////////////////////////////////////////////////// void LLAppViewer::idle() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; pingMainloopTimeout("Main:Idle"); // Update frame timers @@ -4594,8 +4594,7 @@ void LLAppViewer::idle() LLFrameTimer::updateFrameTime(); LLFrameTimer::updateFrameCount(); - LLEventTimer::updateClass(); - LLPerfStats::updateClass(); + LLPerfStats::updateClass(); // LLApp::stepFrame() performs the above three calls plus mRunner.run(). // Not sure why we don't call stepFrame() here, except that LLRunner seems @@ -4607,7 +4606,7 @@ void LLAppViewer::idle() LLDirPickerThread::clearDead(); F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); - LLGLTFMaterialList::flushUpdates(); + LLGLTFMaterialList::flushUpdates(); // Service the WorkQueue we use for replies from worker threads. // Use function statics for the timeslice setting so we only have to fetch diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 4d9ef99319..93a0ef0e82 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -55,7 +55,7 @@ LLDoNotDisturbNotificationStorageTimer::~LLDoNotDisturbNotificationStorageTimer( } -BOOL LLDoNotDisturbNotificationStorageTimer::tick() +bool LLDoNotDisturbNotificationStorageTimer::tick() { LLDoNotDisturbNotificationStorage * doNotDisturbNotificationStorage = LLDoNotDisturbNotificationStorage::getInstance(); @@ -64,7 +64,7 @@ BOOL LLDoNotDisturbNotificationStorageTimer::tick() { doNotDisturbNotificationStorage->saveNotifications(); } - return FALSE; + return false; } LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage() diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index b42c49c607..0bc3c241fa 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -45,7 +45,7 @@ LLFloaterLinkReplace::LLFloaterLinkReplace(const LLSD& key) mTargetUUID(LLUUID::null), mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize")) { - mEventTimer.stop(); + stop(); } LLFloaterLinkReplace::~LLFloaterLinkReplace() @@ -202,7 +202,7 @@ void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, cons mStartBtn->setEnabled(FALSE); mRefreshBtn->setEnabled(FALSE); - mEventTimer.start(); + start(); tick(); } else @@ -298,7 +298,7 @@ void LLFloaterLinkReplace::decreaseOpenItemCount() mStatusText->setText(getString("ReplaceFinished")); mStartBtn->setEnabled(TRUE); mRefreshBtn->setEnabled(TRUE); - mEventTimer.stop(); + stop(); LL_INFOS() << "Inventory link replace finished." << LL_ENDL; } else @@ -310,7 +310,7 @@ void LLFloaterLinkReplace::decreaseOpenItemCount() } } -BOOL LLFloaterLinkReplace::tick() +bool LLFloaterLinkReplace::tick() { LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; @@ -320,7 +320,7 @@ BOOL LLFloaterLinkReplace::tick() { if (!mRemainingInventoryItems.size()) { - mEventTimer.stop(); + stop(); break; } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 34dc263519..d9f7f0a171 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1947,7 +1947,7 @@ public: :LLEventTimer(period), mCallback(cb) { - mEventTimer.stop(); + stop(); } virtual ~Updater(){} @@ -1955,7 +1955,7 @@ public: void update(const LLSD& new_value) { mNewValue = new_value; - mEventTimer.start(); + start(); } protected: @@ -1963,9 +1963,9 @@ protected: bool tick() override { mCallback(mNewValue); - mEventTimer.stop(); + stop(); - return FALSE; + return false; } private: diff --git a/indra/newview/llfloaterregionrestarting.cpp b/indra/newview/llfloaterregionrestarting.cpp index 95d4265bb4..6817cce5f6 100644 --- a/indra/newview/llfloaterregionrestarting.cpp +++ b/indra/newview/llfloaterregionrestarting.cpp @@ -74,11 +74,11 @@ void LLFloaterRegionRestarting::regionChange() close(); } -BOOL LLFloaterRegionRestarting::tick() +bool LLFloaterRegionRestarting::tick() { refresh(); - return FALSE; + return false; } void LLFloaterRegionRestarting::refresh() diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 6da380c639..74b6218b46 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -355,7 +355,7 @@ LLFadeEventTimer::LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent) } // Single tick of fade event timer: increment the color -BOOL LLFadeEventTimer::tick() +bool LLFadeEventTimer::tick() { float diff = 0.04f; if(TRUE == mFadingOut) // set fade for in/out color direction @@ -365,7 +365,7 @@ BOOL LLFadeEventTimer::tick() if(NULL == mParent) // no more need to tick, so suicide { - return TRUE; + return true; } // Set up colors @@ -388,7 +388,7 @@ BOOL LLFadeEventTimer::tick() mFadingOut = FALSE; } - return FALSE; + return false; } // Constructor diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ce4a032b27..0144f13f24 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -99,16 +99,16 @@ const LLUUID LLOutgoingCallDialog::OCD_KEY = LLUUID("7CF78E11-0CFE-498D-ADB9-141 LLIMMgr* gIMMgr = NULL; -BOOL LLSessionTimeoutTimer::tick() +bool LLSessionTimeoutTimer::tick() { - if (mSessionId.isNull()) return TRUE; + if (mSessionId.isNull()) return true; LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); if (session && !session->mSessionInitialized) { gIMMgr->showSessionStartError("session_initialization_timed_out_error", mSessionId); } - return TRUE; + return true; } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 1e42773777..60edbfee88 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -996,23 +996,18 @@ LLLocalBitmapTimer::~LLLocalBitmapTimer() void LLLocalBitmapTimer::startTimer() { - mEventTimer.start(); + start(); } void LLLocalBitmapTimer::stopTimer() { - mEventTimer.stop(); + stop(); } -bool LLLocalBitmapTimer::isRunning() -{ - return mEventTimer.getStarted(); -} - -BOOL LLLocalBitmapTimer::tick() +bool LLLocalBitmapTimer::tick() { LLLocalBitmapMgr::getInstance()->doUpdates(); - return FALSE; + return false; } /*=======================================*/ diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 8420049b1e..96a39a3d66 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -120,7 +120,6 @@ class LLLocalBitmapTimer : public LLEventTimer public: void startTimer(); void stopTimer(); - bool isRunning(); bool tick() override; }; diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp index 61e0163798..91753349c8 100644 --- a/indra/newview/lllocalgltfmaterials.cpp +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -288,24 +288,19 @@ LLLocalGLTFMaterialTimer::~LLLocalGLTFMaterialTimer() void LLLocalGLTFMaterialTimer::startTimer() { - mEventTimer.start(); + start(); } void LLLocalGLTFMaterialTimer::stopTimer() { - mEventTimer.stop(); + stop(); } -bool LLLocalGLTFMaterialTimer::isRunning() -{ - return mEventTimer.getStarted(); -} - -BOOL LLLocalGLTFMaterialTimer::tick() +bool LLLocalGLTFMaterialTimer::tick() { // todo: do on idle? No point in timer LLLocalGLTFMaterialMgr::getInstance()->doUpdates(); - return FALSE; + return false; } /*=======================================*/ diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index 53639dfb1d..ff54d48602 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -89,7 +89,6 @@ public: public: void startTimer(); void stopTimer(); - bool isRunning(); bool tick() override; }; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index d3b981e205..5bf587292d 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -418,10 +418,10 @@ LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc) } // virtual -BOOL LLMediaDataClient::QueueTimer::tick() +bool LLMediaDataClient::QueueTimer::tick() { - BOOL result = TRUE; - + bool result = TRUE; + if (!mMDC.isNull()) { result = mMDC->processQueueTimer(); @@ -451,7 +451,7 @@ LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request) } // virtual -BOOL LLMediaDataClient::RetryTimer::tick() +bool LLMediaDataClient::RetryTimer::tick() { mRequest->stopTracking(); @@ -464,12 +464,12 @@ BOOL LLMediaDataClient::RetryTimer::tick() LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *mRequest << ", retrying." << LL_ENDL; mRequest->reEnqueue(); } - + // Release the ref to the request. - mRequest.reset(); + mRequest.reset(); // Don't fire again - return TRUE; + return true; } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index aad6ceecb2..ab79442f51 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -310,12 +310,12 @@ public: : LLEventTimer(period), LLPanelPeople::Updater(cb) { - mEventTimer.stop(); + stop(); } - virtual bool tick() override // from LLEventTimer + bool tick() override // from LLEventTimer { - return FALSE; + return false; } }; @@ -359,7 +359,7 @@ public: { // events can arrive quickly in bulk - we need not process EVERY one of them - // so we wait a short while to let others pile-in, and process them in aggregate. - mEventTimer.start(); + start(); } // save-up all the mask-bits which have come-in @@ -377,10 +377,10 @@ public: } // Stop updates. - mEventTimer.stop(); + stop(); mMask = 0; - return FALSE; + return false; } // virtual @@ -499,19 +499,19 @@ public: { // update immediately and start regular updates update(); - mEventTimer.start(); + start(); } else { // stop regular updates - mEventTimer.stop(); + stop(); } } bool tick() override { update(); - return FALSE; + return false; } private: }; diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 79d03922cc..a6d628e1ad 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -46,9 +46,7 @@ public: :LLEventTimer(period), mMask(mask), mCallback(cb) - { - mEventTimer.start(); - } + {} virtual ~Updater(){} diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 60bada8f58..2bc8d04a8e 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -181,13 +181,13 @@ LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 acti { } -BOOL LLSpeakerActionTimer::tick() +bool LLSpeakerActionTimer::tick() { if (mActionCallback) { return (BOOL)mActionCallback(mSpeakerId); } - return TRUE; + return true; } void LLSpeakerActionTimer::unset() diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index d30e028d33..d2a650f200 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -57,7 +57,7 @@ void LLToastLifeTimer::restart() bool LLToastLifeTimer::getStarted() { - return LLLater::instance.isRunning(mTimer); + return isRunning(); } void LLToastLifeTimer::setPeriod(F32 period) @@ -326,7 +326,7 @@ void LLToast::setFading(bool transparent) F32 LLToast::getTimeLeftToLive() { - F32 time_to_live = mTimer->getRemainingTimeF32(); + F32 time_to_live = mTimer->getRemaining(); if (!mIsFading) { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b65305337f..e8b81ac3b4 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2901,9 +2901,9 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() { } -BOOL LLPostTeleportNotifiers::tick() +bool LLPostTeleportNotifiers::tick() { - BOOL all_done = FALSE; + bool all_done = false; if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) { // get callingcards and landmarks available to the user arriving. @@ -2927,7 +2927,7 @@ BOOL LLPostTeleportNotifiers::tick() gInventory.addObserver(fetcher); } } - all_done = TRUE; + all_done = true; } return all_done; diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index db8fcb4dc4..8cf86910e7 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -60,7 +60,7 @@ void LLViewerParcelMediaAutoPlay::playStarted() LLSingleton::getInstance()->mPlayed = TRUE; } -BOOL LLViewerParcelMediaAutoPlay::tick() +bool LLViewerParcelMediaAutoPlay::tick() { LLParcel *this_parcel = NULL; LLViewerRegion *this_region = NULL; @@ -156,7 +156,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick() } - return FALSE; // continue ticking forever please. + return false; // continue ticking forever please. } //static -- cgit v1.2.3 From 9f620efa9dd60c5de6b7ea807d53bba922294726 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 3 May 2024 08:52:32 -0400 Subject: Make LLLater store target time in mHandles; ditch 2nd unordered_map. Instead of maintaining a whole separate unordered_map to look up target times, make room in the HandleMap entry for the target time. There's still circularity, but the split into doAtTime1() and doAtTime2() resolves it: since doAtTime2() accepts the mHandles iterator created by doAtTime1(), doAtTime2() can simply store the new mQueue handle_type into the appropriate slot. Also sprinkle in a few more override keywords for consistency. --- indra/llcommon/llcallbacklist.cpp | 50 +++++++++++++++---------------- indra/llcommon/llcallbacklist.h | 10 +++---- indra/newview/llfloaterlinkreplace.h | 4 +-- indra/newview/llfloaterregionrestarting.h | 6 ++-- indra/newview/llpanelpeople.cpp | 12 ++------ 5 files changed, 38 insertions(+), 44 deletions(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 85c73fec8f..19b948a5e1 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -130,33 +130,34 @@ LLCallbackList::handle_t LLCallbackList::doOnIdleRepeating( const bool_func_t& f *****************************************************************************/ LLLater::LLLater() {} -LLLater::DoneMap::iterator LLLater::doAtTime1(LLDate::timestamp time) +LLLater::HandleMap::iterator LLLater::doAtTime1(LLDate::timestamp time) { // Pick token FIRST to store a self-reference in mQueue's managed node as // well as in mHandles. Pre-increment to distinguish 0 from any live // handle_t. token_t token{ ++mToken }; - auto [iter, inserted]{ mDoneTimes.emplace(token, time) }; + // For the moment, store a default-constructed mQueue handle -- + // doAtTime2() will fill in. + auto [iter, inserted]{ mHandles.emplace( + token, + HandleMap::mapped_type{ queue_t::handle_type(), time }) }; llassert(inserted); return iter; } -LLLater::handle_t LLLater::doAtTime2(nullary_func_t callable, DoneMap::iterator iter) +LLLater::handle_t LLLater::doAtTime2(nullary_func_t callable, HandleMap::iterator iter) { bool first{ mQueue.empty() }; - // DoneMap::iterator references (token, time) pair - auto handle{ mQueue.emplace(callable, iter->first, iter->second) }; - auto hiter{ mHandles.emplace(iter->first, handle).first }; - // When called by Periodic, we're passed an existing DoneMap entry, - // meaning the token already exists, meaning emplace() will tell us it - // found an existing entry rather than creating a new one. In that case, - // it's essential to update the handle. - hiter->second = handle; + // HandleMap::iterator references (token, (handle, time)) pair + auto handle{ mQueue.emplace(callable, iter->first, iter->second.second) }; + // Now that we have an mQueue handle_type, store it in mHandles entry. + iter->second.first = handle; if (first) { // If this is our first entry, register for regular callbacks. mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); }); } + // Make an LLLater::handle_t from token. return { iter->first }; } @@ -181,7 +182,7 @@ LLLater::handle_t LLLater::doAfterInterval(nullary_func_t callable, F32 seconds) struct LLLater::Periodic { LLLater* mLater; - DoneMap::iterator mDone; + HandleMap::iterator mHandleEntry; bool_func_t mCallable; F32 mSeconds; @@ -193,9 +194,10 @@ struct LLLater::Periodic // Don't call doAfterInterval(), which rereads LLDate::now(), // since that would defer by however long it took us to wake // up and notice plus however long callable() took to run. - // Bump our mDoneTimes entry so getRemaining() can track. - mDone->second += mSeconds; - mLater->doAtTime2(*this, mDone); + // Bump the time in our mHandles entry so getRemaining() can see. + // HandleMap::iterator references (token, (handle, time)) pair. + mHandleEntry->second.second += mSeconds; + mLater->doAtTime2(*this, mHandleEntry); } } }; @@ -207,7 +209,7 @@ LLLater::handle_t LLLater::doPeriodically(bool_func_t callable, F32 seconds) llassert(seconds > 0); auto iter{ doAtTime1(LLDate::now().secondsSinceEpoch() + seconds) }; // The whole reason we split doAtTime() into doAtTime1() and doAtTime2() - // is to be able to bind the mDoneTimes entry into Periodic. + // is to be able to bind the mHandles entry into Periodic. return doAtTime2(Periodic{ this, iter, callable, seconds }, iter); } @@ -220,14 +222,15 @@ bool LLLater::isRunning(handle_t timer) const F32 LLLater::getRemaining(handle_t timer) const { - auto found{ mDoneTimes.find(timer.token) }; - if (found == mDoneTimes.end()) + auto found{ mHandles.find(timer.token) }; + if (found == mHandles.end()) { return 0.f; } else { - return found->second - LLDate::now().secondsSinceEpoch(); + // HandleMap::iterator references (token, (handle, time)) pair + return found->second.second - LLDate::now().secondsSinceEpoch(); } } @@ -270,12 +273,11 @@ bool LLLater::cancel(const handle_t& timer) return false; } - // erase from mQueue the handle_t referenced by timer.token - mQueue.erase(found->second); + // HandleMap::iterator references (token, (handle, time)) pair. + // Erase from mQueue the handle_type referenced by timer.token. + mQueue.erase(found->second.first); // before erasing timer.token from mHandles mHandles.erase(found); - // don't forget to erase mDoneTimes entry - mDoneTimes.erase(timer.token); if (mQueue.empty()) { // If that was the last active timer, unregister for callbacks. @@ -318,8 +320,6 @@ bool LLLater::tick() auto current{ top }; // remove the mHandles entry referencing this task mHandles.erase(current.mToken); - // and the mDoneTimes entry - mDoneTimes.erase(current.mToken); // before removing the mQueue task entry itself mQueue.pop(); // okay, NOW run diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 17adb7f431..3ff1aad04e 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -241,10 +241,10 @@ private: // the heap aka priority queue queue_t mQueue; // handles we've returned that haven't yet canceled - using HandleMap = std::unordered_map; + using HandleMap = std::unordered_map< + token_t, + std::pair>; HandleMap mHandles; - using DoneMap = std::unordered_map; - DoneMap mDoneTimes; token_t mToken{ 0 }; // While mQueue is non-empty, register for regular callbacks. LLCallbackList::temp_handle_t mLive; @@ -252,8 +252,8 @@ private: struct Periodic; // internal implementation for doAtTime() - DoneMap::iterator doAtTime1(LLDate::timestamp time); - handle_t doAtTime2(nullary_func_t callable, DoneMap::iterator iter); + HandleMap::iterator doAtTime1(LLDate::timestamp time); + handle_t doAtTime2(nullary_func_t callable, HandleMap::iterator iter); }; /*-------------------- legacy names in global namespace --------------------*/ diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index 8d91187a33..a11e025a71 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -86,8 +86,8 @@ public: LLFloaterLinkReplace(const LLSD& key); virtual ~LLFloaterLinkReplace(); - BOOL postBuild(); - virtual void onOpen(const LLSD& key); + BOOL postBuild() override; + void onOpen(const LLSD& key) override; bool tick() override; diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h index d254149e30..6d3639c40c 100644 --- a/indra/newview/llfloaterregionrestarting.h +++ b/indra/newview/llfloaterregionrestarting.h @@ -42,10 +42,10 @@ public: private: LLFloaterRegionRestarting(const LLSD& key); virtual ~LLFloaterRegionRestarting(); - virtual BOOL postBuild(); + BOOL postBuild() override; bool tick() override; - virtual void refresh(); - virtual void draw(); + void refresh() override; + void draw() override; virtual void regionChange(); std::string mName; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index ab79442f51..8efaab034b 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -312,11 +312,6 @@ public: { stop(); } - - bool tick() override // from LLEventTimer - { - return false; - } }; /** @@ -353,7 +348,7 @@ public: LLAvatarTracker::instance().removeObserver(this); } - /*virtual*/ void changed(U32 mask) + void changed(U32 mask) override { if (mIsActive) { @@ -383,8 +378,7 @@ public: return false; } - // virtual - void setActive(bool active) + void setActive(bool active) override { mIsActive = active; if (active) @@ -493,7 +487,7 @@ public: setActive(false); } - /*virtual*/ void setActive(bool val) + void setActive(bool val) override { if (val) { -- cgit v1.2.3 From 5e64fd06a6281eb4b7cc0e30b3d8dae62c264603 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 3 May 2024 09:16:56 -0400 Subject: Not every LLAvatarListUpdater subclass overrides tick(). LLAvatarListUpdater is an LLEventTimer subclass meant to be a base class of still other subclasses. One would presume that every one of them should override tick(), since LLAvatarListUpdater::tick() is a no-op that simply asks to be called again. But making it abstract (=0) produces errors since at least one subclass does not define its own tick() method. This seems less than useful, since the specific tick() method is the whole point of deriving from LLEventTimer, but oh well. --- indra/newview/llpanelpeople.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 8efaab034b..b342fa5549 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -312,6 +312,11 @@ public: { stop(); } + + bool tick() override // from LLEventTimer + { + return false; + } }; /** -- cgit v1.2.3 From 922277764d41e96a1c41291272bb70e3a1b8c677 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 3 May 2024 09:27:16 -0400 Subject: Prevent LLLater from thrashing on LLCallbackList. If there is exactly one doPeriodically() entry on LLLater, the mQueue entry is deleted before Periodic::operator()() is called. If Periodic's callable returns false, it reinstates itself on mQueue for a future time. That's okay, because the test for mQueue.empty(), and the consequent disconnect from LLCallbackList, happens only after that Periodic call returns. But at the moment Periodic reinstates itself on mQueue, mQueue happens to be empty. That alerts doAtTime2() to register itself on LLCallbackList -- even though at that moment it's already registered. Semantically that's okay because assigning to the LLLater's LLCallbackList::temp_handle_t should implicitly disconnect the previous connection. But it's pointless to create a new connection and disconnect the old one every time we call that lone Periodic. Add a test for mLive.connected(); that way if we already have an LLCallbackList connection, we retain it instead of replacing it with a new one. --- indra/llcommon/llcallbacklist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 19b948a5e1..992c83b4d2 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -152,7 +152,7 @@ LLLater::handle_t LLLater::doAtTime2(nullary_func_t callable, HandleMap::iterato auto handle{ mQueue.emplace(callable, iter->first, iter->second.second) }; // Now that we have an mQueue handle_type, store it in mHandles entry. iter->second.first = handle; - if (first) + if (first && ! mLive.connected()) { // If this is our first entry, register for regular callbacks. mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); }); -- cgit v1.2.3 From c89d51c60a6f42a5e279e2c9e06adcf1f13822c0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 3 May 2024 11:46:00 -0400 Subject: Log a stack trace on LL_ERRS(). --- indra/llcommon/llerror.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 0f48ce16b2..ccdf3b60a8 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -44,6 +44,8 @@ # include #endif // !LL_WINDOWS #include +#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED +#include #include "string.h" #include "llapp.h" @@ -1429,16 +1431,17 @@ namespace LLError message_stream << message; message = message_stream.str(); } - + writeToRecorders(site, message); if (site.mLevel == LEVEL_ERROR) { + writeToRecorders(site, stringize(boost::stacktrace::stacktrace())); g->mFatalMessage = message; - if (s->mCrashFunction) - { - s->mCrashFunction(message); - } + if (s->mCrashFunction) + { + s->mCrashFunction(message); + } } } } -- cgit v1.2.3 From d4f384b4ec55758a7f2ca4338894ea6cacc98eec Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 7 May 2024 16:13:03 -0400 Subject: Refactor LLLater -> LL::Timers to accommodate nonpositive repeats. In the previous design, the tick() method ran each task exactly once. doPeriodically() was implemented by posting a functor that would, after calling the specified callable, repost itself at (timestamp + interval). The trouble with that design is that it required (interval > 0). A nonpositive interval would result in looping over any timers with nonpositive repetition intervals without ever returning from the tick() method. To avoid that, doPeriodically() contained an llassert(interval > 0). Unfortunately the viewer failed that constraint immediately at login, leading to the suspicion that eliminating every such usage might require a protracted search. Lifting that restriction required a redesign. Now the priority queue stores a callable returning bool, and the tick() method itself contains the logic to repost a recurring task -- but defers doing so until after it stops looping over ready tasks, ensuring that a task with a nonpositive interval will at least wait until the following tick() call. This simplifies not only doPeriodically(), but also doAtTime(). The previous split of doAtTime() into doAtTime1() and doAtTime2() was only to accommodate the needs of the Periodic functor class. Ditch Periodic. Per feedback from NickyD, rename doAtTime() to scheduleAt(), which wraps its passed nullary callable into a callable that unconditionally returns true (so tick() will run it only once). Rename the doAfterInterval() method to scheduleAfter(), which similarly wraps its nullary callable. However, the legacy doAfterInterval() free function remains. scheduleAfter() also loses its llassert(seconds > 0). Rename the doPeriodically() method to scheduleRepeating(). However, the legacy doPeriodically() free function remains. Add internal scheduleAtRepeating(), whose role is to accept both a specific timestamp and a repetition interval (which might be ignored, depending on the callable). scheduleAtRepeating() now contains the real logic to add a task. Rename getRemaining() to timeUntilCall(), hopefully resolving the question of "remaining what?" Expand the std::pair metadata stored in Timers's auxiliary unordered_map to a Metadata struct containing the repetition interval plus two bools to mediate deferred cancel() processing. Rename HandleMap to MetaMap, mHandles to mMeta. Defend against the case when cancel(handle) is reached during the call to that handle's callable. Meta::mRunning is set for the duration of that call. When cancel() sees mRunning, instead of immediately deleting map entries, it sets mCancel. Upon return from a task's callable, tick() notices mCancel and behaves as if the callable returned true to stop the series of calls. To guarantee that mRunning doesn't inadvertently remain set even in the case of an exception, introduce local RAII class TempSet whose constructor accepts a non-const variable reference and a desired value. The constructor captures the current value and sets the desired value; the destructor restores the previous value. Defend against exception in a task's callable, and stop calling that task. Use LOG_UNHANDLED_EXCEPTION() to report it. --- indra/llcommon/llcallbacklist.cpp | 266 +++++++++++++++++++++++--------------- indra/llcommon/llcallbacklist.h | 94 +++++++++----- indra/llcommon/lleventfilter.cpp | 10 +- indra/llcommon/lleventfilter.h | 4 +- indra/llcommon/lleventtimer.cpp | 8 +- indra/llcommon/lleventtimer.h | 2 +- 6 files changed, 233 insertions(+), 151 deletions(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 992c83b4d2..52e9860e02 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -25,6 +25,8 @@ */ #include "llcallbacklist.h" +#include "llexception.h" +#include // // Member functions @@ -126,116 +128,83 @@ LLCallbackList::handle_t LLCallbackList::doOnIdleRepeating( const bool_func_t& f } /***************************************************************************** -* LLLater +* LL::Timers *****************************************************************************/ -LLLater::LLLater() {} - -LLLater::HandleMap::iterator LLLater::doAtTime1(LLDate::timestamp time) +namespace LL { - // Pick token FIRST to store a self-reference in mQueue's managed node as - // well as in mHandles. Pre-increment to distinguish 0 from any live - // handle_t. - token_t token{ ++mToken }; - // For the moment, store a default-constructed mQueue handle -- - // doAtTime2() will fill in. - auto [iter, inserted]{ mHandles.emplace( - token, - HandleMap::mapped_type{ queue_t::handle_type(), time }) }; - llassert(inserted); - return iter; -} -LLLater::handle_t LLLater::doAtTime2(nullary_func_t callable, HandleMap::iterator iter) -{ - bool first{ mQueue.empty() }; - // HandleMap::iterator references (token, (handle, time)) pair - auto handle{ mQueue.emplace(callable, iter->first, iter->second.second) }; - // Now that we have an mQueue handle_type, store it in mHandles entry. - iter->second.first = handle; - if (first && ! mLive.connected()) - { - // If this is our first entry, register for regular callbacks. - mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); }); - } - // Make an LLLater::handle_t from token. - return { iter->first }; -} +Timers::Timers() {} // Call a given callable once at specified timestamp. -LLLater::handle_t LLLater::doAtTime(nullary_func_t callable, LLDate::timestamp time) +Timers::handle_t Timers::scheduleAt(nullary_func_t callable, LLDate::timestamp time) { - return doAtTime2(callable, doAtTime1(time)); + // tick() assumes you want to run periodically until you return true. + // Schedule a task that returns true after a single call. + return scheduleAtRepeating(once(callable), time, 0); } // Call a given callable once after specified interval. -LLLater::handle_t LLLater::doAfterInterval(nullary_func_t callable, F32 seconds) +Timers::handle_t Timers::scheduleAfter(nullary_func_t callable, F32 seconds) { - // Passing 0 is a slightly more expensive way of calling - // LLCallbackList::doOnIdleOneTime(). Are we sure the caller is correct? - // (If there's a valid use case, remove the llassert() and carry on.) - llassert(seconds > 0); - return doAtTime(callable, LLDate::now().secondsSinceEpoch() + seconds); + return scheduleRepeating(once(callable), seconds); } -// For doPeriodically(), we need a struct rather than a lambda because a -// struct, unlike a lambda, has access to 'this'. -struct LLLater::Periodic +// Call a given callable every specified number of seconds, until it returns true. +Timers::handle_t Timers::scheduleRepeating(bool_func_t callable, F32 seconds) { - LLLater* mLater; - HandleMap::iterator mHandleEntry; - bool_func_t mCallable; - F32 mSeconds; + return scheduleAtRepeating(callable, now() + seconds, seconds); +} - void operator()() +Timers::handle_t Timers::scheduleAtRepeating(bool_func_t callable, + LLDate::timestamp time, F32 interval) +{ + // Pick token FIRST to store a self-reference in mQueue's managed node as + // well as in mMeta. Pre-increment to distinguish 0 from any live + // handle_t. + token_t token{ ++mToken }; + // For the moment, store a default-constructed mQueue handle -- + // we'll fill in later. + auto [iter, inserted] = mMeta.emplace(token, + Metadata{ queue_t::handle_type(), time, interval }); + // It's important that our token is unique. + llassert(inserted); + + // Remember whether this is the first entry in mQueue + bool first{ mQueue.empty() }; + auto handle{ mQueue.emplace(callable, token, time) }; + // Now that we have an mQueue handle_type, store it in mMeta entry. + iter->second.mHandle = handle; + if (first && ! mLive.connected()) { - if (! mCallable()) - { - // Returning false means please schedule another call. - // Don't call doAfterInterval(), which rereads LLDate::now(), - // since that would defer by however long it took us to wake - // up and notice plus however long callable() took to run. - // Bump the time in our mHandles entry so getRemaining() can see. - // HandleMap::iterator references (token, (handle, time)) pair. - mHandleEntry->second.second += mSeconds; - mLater->doAtTime2(*this, mHandleEntry); - } + // If this is our first entry, register for regular callbacks. + mLive = LLCallbackList::instance().doOnIdleRepeating([this]{ return tick(); }); } -}; - -// Call a given callable every specified number of seconds, until it returns true. -LLLater::handle_t LLLater::doPeriodically(bool_func_t callable, F32 seconds) -{ - // Passing seconds <= 0 will produce an infinite loop. - llassert(seconds > 0); - auto iter{ doAtTime1(LLDate::now().secondsSinceEpoch() + seconds) }; - // The whole reason we split doAtTime() into doAtTime1() and doAtTime2() - // is to be able to bind the mHandles entry into Periodic. - return doAtTime2(Periodic{ this, iter, callable, seconds }, iter); + // Make an Timers::handle_t from token. + return { token }; } -bool LLLater::isRunning(handle_t timer) const +bool Timers::isRunning(handle_t timer) const { // A default-constructed timer isn't running. - // A timer we don't find in mHandles has fired or been canceled. - return timer && mHandles.find(timer.token) != mHandles.end(); + // A timer we don't find in mMeta has fired or been canceled. + return timer && mMeta.find(timer.token) != mMeta.end(); } -F32 LLLater::getRemaining(handle_t timer) const +F32 Timers::timeUntilCall(handle_t timer) const { - auto found{ mHandles.find(timer.token) }; - if (found == mHandles.end()) + MetaMap::const_iterator found; + if ((! timer) || (found = mMeta.find(timer.token)) == mMeta.end()) { return 0.f; } else { - // HandleMap::iterator references (token, (handle, time)) pair - return found->second.second - LLDate::now().secondsSinceEpoch(); + return found->second.mTime - now(); } } -// Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically() -bool LLLater::cancel(handle_t& timer) +// Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleRepeating() +bool Timers::cancel(handle_t& timer) { // For exception safety, capture and clear timer before canceling. // Once we've canceled this handle, don't retain the live handle. @@ -244,7 +213,7 @@ bool LLLater::cancel(handle_t& timer) return cancel(ctimer); } -bool LLLater::cancel(const handle_t& timer) +bool Timers::cancel(const handle_t& timer) { if (! timer) { @@ -257,27 +226,38 @@ bool LLLater::cancel(const handle_t& timer) // Nor do we find any documented way to ask whether a given handle still // tracks a valid heap node. That's why we capture all returned handles in - // mHandles and validate against that collection. What about the pop() + // mMeta and validate against that collection. What about the pop() // call in tick()? How to map from the top() value back to the // corresponding handle_t? That's why we store func_at::mToken. // fibonacci_heap provides a pair of begin()/end() methods to iterate over // all nodes (NOT in heap order), plus a function to convert from such - // iterators to handles. Without mHandles, that would be our only chance + // iterators to handles. Without mMeta, that would be our only chance // to validate. - auto found{ mHandles.find(timer.token) }; - if (found == mHandles.end()) + auto found{ mMeta.find(timer.token) }; + if (found == mMeta.end()) { // we don't recognize this handle -- maybe the timer has already // fired, maybe it was previously canceled. return false; } - // HandleMap::iterator references (token, (handle, time)) pair. + // Funny case: what if the callback directly or indirectly reaches a + // cancel() call for its own handle? + if (found->second.mRunning) + { + // tick() has special logic to defer the actual deletion until the + // callback has returned + found->second.mCancel = true; + // this handle does in fact reference a live timer, + // which we're going to cancel when we get a chance + return true; + } + // Erase from mQueue the handle_type referenced by timer.token. - mQueue.erase(found->second.first); - // before erasing timer.token from mHandles - mHandles.erase(found); + mQueue.erase(found->second.mHandle); + // before erasing the mMeta entry + mMeta.erase(found); if (mQueue.empty()) { // If that was the last active timer, unregister for callbacks. @@ -289,7 +269,33 @@ bool LLLater::cancel(const handle_t& timer) return true; } -bool LLLater::tick() +// RAII class to set specified variable to specified value +// only for the duration of containing scope +template +class TempSet +{ +public: + TempSet(VAR& var, const VALUE& value): + mVar(var), + mOldValue(mVar) + { + mVar = value; + } + + TempSet(const TempSet&) = delete; + TempSet& operator=(const TempSet&) = delete; + + ~TempSet() + { + mVar = mOldValue; + } + +private: + VAR& mVar; + VALUE mOldValue; +}; + +bool Timers::tick() { // Fetch current time only on entry, even though running some mQueue task // may take long enough that the next one after would become ready. We're @@ -297,34 +303,84 @@ bool LLLater::tick() // starve it if we have a sequence of tasks that take nontrivial time. auto now{ LLDate::now().secondsSinceEpoch() }; auto cutoff{ now + TIMESLICE }; + + // Capture tasks we've processed but that want to be rescheduled. + // Defer rescheduling them immediately to avoid getting stuck looping over + // a recurring task with a nonpositive interval. + std::vector> deferred; + while (! mQueue.empty()) { auto& top{ mQueue.top() }; if (top.mTime > now) { // we've hit an entry that's still in the future: - // done with this tick(), but schedule another call - return false; + // done with this tick() + break; } if (LLDate::now().secondsSinceEpoch() > cutoff) { // we still have ready tasks, but we've already eaten too much - // time this tick() -- defer until next tick() -- call again - return false; + // time this tick() -- defer until next tick() + break; } - // Found a ready task. Hate to copy stuff, but -- what if the task - // indirectly ends up trying to cancel a handle referencing its own - // node in mQueue? If the task has any state, that would be Bad. Copy - // the node before running it. - auto current{ top }; - // remove the mHandles entry referencing this task - mHandles.erase(current.mToken); - // before removing the mQueue task entry itself + // Found a ready task. Look up its corresponding mMeta entry. + auto meta{ mMeta.find(top.mToken) }; + llassert(meta != mMeta.end()); + bool done; + { + // Mark our mMeta entry so we don't cancel this timer while its + // callback is running, but unmark it even in case of exception. + TempSet running(meta->second.mRunning, true); + // run the callback and capture its desire to end repetition + try + { + done = top.mFunc(); + } + catch (...) + { + // Don't crash if a timer callable throws. + // But don't continue calling that callable, either. + done = true; + LOG_UNHANDLED_EXCEPTION("LL::Timers"); + } + } // clear mRunning + + // If mFunc() returned true (all done, stop calling me) or + // meta->mCancel (somebody tried to cancel this timer during the + // callback call), then we're done: clean up both entries. + if (done || meta->second.mCancel) + { + // remove the mMeta entry referencing this task + mMeta.erase(meta); + } + else + { + // mFunc returned false, and nobody asked to cancel: + // continue calling this task at a future time. + meta->second.mTime += meta->second.mInterval; + // capture this task to reschedule once we break loop + deferred.push_back({meta, top}); + // update func_at's mTime to match meta's + deferred.back().second.mTime = meta->second.mTime; + } + // Remove the mQueue entry regardless, or we risk stalling the + // queue right here if we have a nonpositive interval. mQueue.pop(); - // okay, NOW run - current.mFunc(); } - // queue is empty: stop callbacks - return true; + + // Now reschedule any tasks that need to be rescheduled. + for (const auto& [meta, task] : deferred) + { + auto handle{ mQueue.push(task) }; + // track this new mQueue handle_type + meta->second.mHandle = handle; + } + + // If, after all the twiddling above, our queue ended up empty, + // stop calling every tick. + return mQueue.empty(); } + +} // namespace LL diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 3ff1aad04e..f9b15867ef 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -101,11 +101,14 @@ LLCallbackList::handle_t doOnIdleRepeating(bool_func_t callable) } /***************************************************************************** -* LLLater: callbacks at some future time +* LL::Timers: callbacks at some future time *****************************************************************************/ -class LLLater: public LLSingleton +namespace LL { - LLSINGLETON(LLLater); + +class Timers: public LLSingleton +{ + LLSINGLETON(Timers); using token_t = U32; @@ -113,11 +116,14 @@ class LLLater: public LLSingleton // a tuple, because we need to define the comparison operator. struct func_at { - nullary_func_t mFunc; + // callback to run when this timer fires + bool_func_t mFunc; + // key to look up metadata in mHandles token_t mToken; + // time at which this timer is supposed to fire LLDate::timestamp mTime; - func_at(const nullary_func_t& func, token_t token, LLDate::timestamp tm): + func_at(const bool_func_t& func, token_t token, LLDate::timestamp tm): mFunc(func), mToken(token), mTime(tm) @@ -146,7 +152,7 @@ public: class handle_t { private: - friend class LLLater; + friend class Timers; token_t token; public: handle_t(token_t token=0): token(token) {} @@ -156,33 +162,33 @@ public: }; // Call a given callable once at specified timestamp. - handle_t doAtTime(nullary_func_t callable, LLDate::timestamp time); + handle_t scheduleAt(nullary_func_t callable, LLDate::timestamp time); // Call a given callable once after specified interval. - handle_t doAfterInterval(nullary_func_t callable, F32 seconds); + handle_t scheduleAfter(nullary_func_t callable, F32 seconds); // Call a given callable every specified number of seconds, until it returns true. - handle_t doPeriodically(bool_func_t callable, F32 seconds); + handle_t scheduleRepeating(bool_func_t callable, F32 seconds); // test whether specified handle is still live bool isRunning(handle_t timer) const; // check remaining time - F32 getRemaining(handle_t timer) const; + F32 timeUntilCall(handle_t timer) const; - // Cancel a future timer set by doAtTime(), doAfterInterval(), doPeriodically(). - // Return true iff the handle corresponds to a live timer. + // Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleRepeating(). + // Return true if and only if the handle corresponds to a live timer. bool cancel(const handle_t& timer); // If we're canceling a non-const handle_t, also clear it so we need not // cancel again. bool cancel(handle_t& timer); - // Store a handle_t returned by doAtTime(), doAfterInterval() or - // doPeriodically() in a temp_handle_t to cancel() automatically on + // Store a handle_t returned by scheduleAt(), scheduleAfter() or + // scheduleRepeating() in a temp_handle_t to cancel() automatically on // destruction of the temp_handle_t. class temp_handle_t { public: - temp_handle_t() {} + temp_handle_t() = default; temp_handle_t(const handle_t& hdl): mHandle(hdl) {} temp_handle_t(const temp_handle_t&) = delete; temp_handle_t(temp_handle_t&&) = default; @@ -204,11 +210,11 @@ public: // temp_handle_t should be usable wherever handle_t is operator handle_t() const { return mHandle; } // If we're dealing with a non-const temp_handle_t, pass a reference - // to our handle_t member (e.g. to LLLater::cancel()). + // to our handle_t member (e.g. to Timers::cancel()). operator handle_t&() { return mHandle; } // For those in the know, provide a cancel() method of our own that - // avoids LLLater::instance() lookup when mHandle isn't live. + // avoids Timers::instance() lookup when mHandle isn't live. bool cancel() { if (! mHandle) @@ -217,7 +223,7 @@ public: } else { - return LLLater::instance().cancel(mHandle); + return Timers::instance().cancel(mHandle); } } @@ -231,44 +237,64 @@ public: }; private: + handle_t scheduleAtRepeating(bool_func_t callable, LLDate::timestamp time, F32 interval); + LLDate::timestamp now() const { return LLDate::now().secondsSinceEpoch(); } + // wrap a nullary_func_t with a bool_func_t that will only execute once + bool_func_t once(nullary_func_t callable) + { + return [callable] + { + callable(); + return true; + }; + } bool tick(); // NOTE: We don't lock our data members because it doesn't make sense to - // register cross-thread callbacks. If we start wanting to use them on + // register cross-thread callbacks. If we start wanting to use Timers on // threads other than the main thread, it would make more sense to make // our data members thread_local than to lock them. // the heap aka priority queue queue_t mQueue; - // handles we've returned that haven't yet canceled - using HandleMap = std::unordered_map< - token_t, - std::pair>; - HandleMap mHandles; + + // metadata about a given task + struct Metadata + { + // handle to mQueue entry + queue_t::handle_type mHandle; + // time at which this timer is supposed to fire + LLDate::timestamp mTime; + // interval at which this timer is supposed to fire repeatedly + F32 mInterval{ 0 }; + // mFunc is currently running: don't delete this entry + bool mRunning{ false }; + // cancel() was called while mFunc was running: deferred cancel + bool mCancel{ false }; + }; + + using MetaMap = std::unordered_map; + MetaMap mMeta; token_t mToken{ 0 }; // While mQueue is non-empty, register for regular callbacks. LLCallbackList::temp_handle_t mLive; - - struct Periodic; - - // internal implementation for doAtTime() - HandleMap::iterator doAtTime1(LLDate::timestamp time); - handle_t doAtTime2(nullary_func_t callable, HandleMap::iterator iter); }; +} // namespace LL + /*-------------------- legacy names in global namespace --------------------*/ // Call a given callable once after specified interval. inline -LLLater::handle_t doAfterInterval(nullary_func_t callable, F32 seconds) +LL::Timers::handle_t doAfterInterval(nullary_func_t callable, F32 seconds) { - return LLLater::instance().doAfterInterval(callable, seconds); + return LL::Timers::instance().scheduleAfter(callable, seconds); } // Call a given callable every specified number of seconds, until it returns true. inline -LLLater::handle_t doPeriodically(bool_func_t callable, F32 seconds) +LL::Timers::handle_t doPeriodically(bool_func_t callable, F32 seconds) { - return LLLater::instance().doPeriodically(callable, seconds); + return LL::Timers::instance().scheduleRepeating(callable, seconds); } #endif diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index e72ae7ad33..ad61e9298a 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -87,7 +87,7 @@ LLEventTimeout::LLEventTimeout(LLEventPump& source): void LLEventTimeout::actionAfter(F32 seconds, const Action& action) { - mTimer = LLLater::instance().doAfterInterval(action, seconds); + mTimer = LL::Timers::instance().scheduleAfter(action, seconds); } void LLEventTimeout::errorAfter(F32 seconds, const std::string& message) @@ -118,7 +118,7 @@ void LLEventTimeout::cancel() bool LLEventTimeout::running() const { - return LLLater::instance().isRunning(mTimer); + return LL::Timers::instance().isRunning(mTimer); } /***************************************************************************** @@ -277,17 +277,17 @@ F32 LLEventThrottle::getDelay() const void LLEventThrottle::alarmActionAfter(F32 interval, const LLEventTimeout::Action& action) { - mAlarm = LLLater::instance().doAfterInterval(action, interval); + mAlarm = LL::Timers::instance().scheduleAfter(action, interval); } bool LLEventThrottle::alarmRunning() const { - return LLLater::instance().isRunning(mAlarm); + return LL::Timers::instance().isRunning(mAlarm); } void LLEventThrottle::alarmCancel() { - LLLater::instance().cancel(mAlarm); + LL::Timers::instance().cancel(mAlarm); } void LLEventThrottle::timerSet(F32 interval) diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 1deb6f0f4c..b39791c560 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -191,7 +191,7 @@ public: private: // Use a temp_handle_t so it's canceled on destruction. - LLLater::temp_handle_t mTimer; + LL::Timers::temp_handle_t mTimer; }; /** @@ -300,7 +300,7 @@ private: F32 mInterval; // use this to arrange a deferred flush() call - LLLater::handle_t mAlarm; + LL::Timers::handle_t mAlarm; }; /** diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index 0f8d1e636f..1d2da93683 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -49,20 +49,20 @@ LLEventTimer::~LLEventTimer() void LLEventTimer::start() { - mTimer = LLLater::instance().doPeriodically([this]{ return tick(); }, mPeriod); + mTimer = LL::Timers::instance().scheduleRepeating([this]{ return tick(); }, mPeriod); } void LLEventTimer::stop() { - LLLater::instance().cancel(mTimer); + LL::Timers::instance().cancel(mTimer); } bool LLEventTimer::isRunning() { - return LLLater::instance().isRunning(mTimer); + return LL::Timers::instance().isRunning(mTimer); } F32 LLEventTimer::getRemaining() { - return LLLater::instance().getRemaining(mTimer); + return LL::Timers::instance().timeUntilCall(mTimer); } diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index 05d8bc038d..a325c704e0 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -50,7 +50,7 @@ public: virtual bool tick() = 0; protected: - LLLater::temp_handle_t mTimer; + LL::Timers::temp_handle_t mTimer; F32 mPeriod; }; -- cgit v1.2.3 From b400f83deb068060f9dde5c0a2d6d1a259191ddd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 8 May 2024 13:59:21 -0400 Subject: Fix llerror_test.cpp now that LL_ERRS() includes a stacktrace. --- indra/llcommon/llerror.cpp | 2 - indra/llcommon/tests/llerror_test.cpp | 247 ++++++++++++++++++++-------------- 2 files changed, 145 insertions(+), 104 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index ccdf3b60a8..b6285db073 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -44,8 +44,6 @@ # include #endif // !LL_WINDOWS #include -#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED -#include #include "string.h" #include "llapp.h" diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index b4cdbdc6bf..63d5bdbb70 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -112,10 +112,10 @@ namespace tut mMessages.push_back(message); } - int countMessages() { return (int) mMessages.size(); } + int countMessages() const { return (int) mMessages.size(); } void clearMessages() { mMessages.clear(); } - std::string message(int n) + std::string message(int n) const { std::ostringstream test_name; test_name << "testing message " << n << ", not enough messages"; @@ -124,6 +124,16 @@ namespace tut return mMessages[n]; } + void reportMessages() const + { + std::cerr << '\n'; + int n = 0; + for (const auto& msg : mMessages) + { + std::cerr << std::setw(2) << n++ << ": " << msg.substr(0, 100) << '\n'; + } + } + private: typedef std::vector MessageVector; MessageVector mMessages; @@ -134,6 +144,8 @@ namespace tut LLError::RecorderPtr mRecorder; LLError::SettingsStoragePtr mPriorErrorSettings; + auto recorder() { return std::dynamic_pointer_cast(mRecorder); } + ErrorTestData(): mRecorder(new TestRecorder()) { @@ -153,27 +165,32 @@ namespace tut int countMessages() { - return std::dynamic_pointer_cast(mRecorder)->countMessages(); + return recorder()->countMessages(); } void clearMessages() { - std::dynamic_pointer_cast(mRecorder)->clearMessages(); + recorder()->clearMessages(); } void setWantsTime(bool t) - { - std::dynamic_pointer_cast(mRecorder)->showTime(t); - } + { + recorder()->showTime(t); + } void setWantsMultiline(bool t) - { - std::dynamic_pointer_cast(mRecorder)->showMultiline(t); - } + { + recorder()->showMultiline(t); + } std::string message(int n) { - return std::dynamic_pointer_cast(mRecorder)->message(n); + return recorder()->message(n); + } + + void reportMessages() + { + recorder()->reportMessages(); } void ensure_message_count(int expectedCount) @@ -181,71 +198,87 @@ namespace tut ensure_equals("message count", countMessages(), expectedCount); } - std::string message_field(int msgnum, LogFieldIndex fieldnum) - { - std::ostringstream test_name; - test_name << "testing message " << msgnum << ", not enough messages"; - tut::ensure(test_name.str(), msgnum < countMessages()); - - std::string msg(message(msgnum)); - - std::string field_value; - - // find the start of the field; fields are separated by a single space - size_t scan = 0; - int on_field = 0; - while ( scan < msg.length() && on_field < fieldnum ) - { - // fields are delimited by one space - if ( ' ' == msg[scan] ) - { - if ( on_field < FUNCTION_FIELD ) - { - on_field++; - } - // except function, which may have embedded spaces so ends with " : " - else if ( ( on_field == FUNCTION_FIELD ) - && ( ':' == msg[scan+1] && ' ' == msg[scan+2] ) - ) - { - on_field++; - scan +=2; - } - } - scan++; - } - size_t start_field = scan; - size_t fieldlen = 0; - if ( fieldnum < FUNCTION_FIELD ) - { - fieldlen = msg.find(' ', start_field) - start_field; - } - else if ( fieldnum == FUNCTION_FIELD ) - { - fieldlen = msg.find(" : ", start_field) - start_field; - } - else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end - { - fieldlen = msg.length() - start_field; - } - - return msg.substr(start_field, fieldlen); - } - + std::string message_field(int msgnum, LogFieldIndex fieldnum) + { + std::ostringstream test_name; + test_name << "testing message " << msgnum << ", not enough messages"; + tut::ensure(test_name.str(), msgnum < countMessages()); + + std::string msg(message(msgnum)); + + std::string field_value; + + // find the start of the field; fields are separated by a single space + size_t scan = 0; + int on_field = 0; + while ( scan < msg.length() && on_field < fieldnum ) + { + // fields are delimited by one space + if ( ' ' == msg[scan] ) + { + if ( on_field < FUNCTION_FIELD ) + { + on_field++; + } + // except function, which may have embedded spaces so ends with " : " + else if (( on_field == FUNCTION_FIELD ) + && ( ':' == msg[scan+1] && ' ' == msg[scan+2] ) + ) + { + on_field++; + scan +=2; + } + } + scan++; + } + size_t start_field = scan; + size_t fieldlen = 0; + if ( fieldnum < FUNCTION_FIELD ) + { + fieldlen = msg.find(' ', start_field) - start_field; + } + else if ( fieldnum == FUNCTION_FIELD ) + { + fieldlen = msg.find(" : ", start_field) - start_field; + } + else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end + { + fieldlen = msg.length() - start_field; + } + + return msg.substr(start_field, fieldlen); + } + void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) - { - std::ostringstream test_name; - test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum) << "\"\n "; + { + std::ostringstream test_name; + test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum).substr(0, 100) << "\"\n "; - ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText); - } + try + { + ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText); + } + catch (const failure&) + { + reportMessages(); + throw; + } + } void ensure_message_does_not_contain(int n, const std::string& expectedText) { std::ostringstream test_name; test_name << "testing message " << n; - ensure_does_not_contain(test_name.str(), message(n), expectedText); + try + { + ensure_does_not_contain(test_name.str(), message(n), expectedText); + } + catch (const failure&) + { + reportMessages(); + throw; + } } }; @@ -297,29 +330,33 @@ namespace tut ensure_message_field_equals(3, MSG_FIELD, "four"); ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); - ensure_message_count(4); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(5); LLError::setDefaultLevel(LLError::LEVEL_INFO); writeSome(); - ensure_message_field_equals(4, MSG_FIELD, "two"); - ensure_message_field_equals(5, MSG_FIELD, "three"); - ensure_message_field_equals(6, MSG_FIELD, "four"); - ensure_message_count(7); + ensure_message_field_equals(5, MSG_FIELD, "two"); + ensure_message_field_equals(6, MSG_FIELD, "three"); + ensure_message_field_equals(7, MSG_FIELD, "four"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(9); LLError::setDefaultLevel(LLError::LEVEL_WARN); writeSome(); - ensure_message_field_equals(7, MSG_FIELD, "three"); - ensure_message_field_equals(8, MSG_FIELD, "four"); - ensure_message_count(9); + ensure_message_field_equals(9, MSG_FIELD, "three"); + ensure_message_field_equals(10, MSG_FIELD, "four"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(12); LLError::setDefaultLevel(LLError::LEVEL_ERROR); writeSome(); - ensure_message_field_equals(9, MSG_FIELD, "four"); - ensure_message_count(10); + ensure_message_field_equals(12, MSG_FIELD, "four"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(14); LLError::setDefaultLevel(LLError::LEVEL_NONE); writeSome(); - ensure_message_count(10); + ensure_message_count(14); } template<> template<> @@ -331,7 +368,8 @@ namespace tut ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - ensure_message_count(4); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(5); } template<> template<> @@ -339,20 +377,20 @@ namespace tut // file abbreviation { std::string prev, abbreviateFile = __FILE__; - do - { - prev = abbreviateFile; - abbreviateFile = LLError::abbreviateFile(abbreviateFile); - // __FILE__ is assumed to end with - // indra/llcommon/tests/llerror_test.cpp. This test used to call - // abbreviateFile() exactly once, then check below whether it - // still contained the string 'indra'. That fails if the FIRST - // part of the pathname also contains indra! Certain developer - // machine images put local directory trees under - // /ngi-persist/indra, which is where we observe the problem. So - // now, keep calling abbreviateFile() until it returns its - // argument unchanged, THEN check. - } while (abbreviateFile != prev); + do + { + prev = abbreviateFile; + abbreviateFile = LLError::abbreviateFile(abbreviateFile); + // __FILE__ is assumed to end with + // indra/llcommon/tests/llerror_test.cpp. This test used to call + // abbreviateFile() exactly once, then check below whether it + // still contained the string 'indra'. That fails if the FIRST + // part of the pathname also contains indra! Certain developer + // machine images put local directory trees under + // /ngi-persist/indra, which is where we observe the problem. So + // now, keep calling abbreviateFile() until it returns its + // argument unchanged, THEN check. + } while (abbreviateFile != prev); ensure_ends_with("file name abbreviation", abbreviateFile, @@ -627,7 +665,8 @@ namespace tut ensure_message_field_equals(0, LOCATION_FIELD, location); ensure_message_field_equals(0, MSG_FIELD, "die"); - ensure_message_count(1); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(2); ensure("fatal callback called", fatalWasCalled); } @@ -751,10 +790,12 @@ namespace tut ensure_message_field_equals(0, MSG_FIELD, "aim west"); ensure_message_field_equals(1, MSG_FIELD, "ate eels"); - ensure_message_field_equals(2, MSG_FIELD, "buy iron"); - ensure_message_field_equals(3, MSG_FIELD, "bad word"); - ensure_message_field_equals(4, MSG_FIELD, "big easy"); - ensure_message_count(5); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_field_equals(3, MSG_FIELD, "buy iron"); + ensure_message_field_equals(4, MSG_FIELD, "bad word"); + ensure_message_field_equals(5, MSG_FIELD, "big easy"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(7); } template<> template<> @@ -868,9 +909,11 @@ namespace tut TestBeta::doAll(); ensure_message_field_equals(3, MSG_FIELD, "aim west"); ensure_message_field_equals(4, MSG_FIELD, "ate eels"); - ensure_message_field_equals(5, MSG_FIELD, "bad word"); - ensure_message_field_equals(6, MSG_FIELD, "big easy"); - ensure_message_count(7); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_field_equals(6, MSG_FIELD, "bad word"); + ensure_message_field_equals(7, MSG_FIELD, "big easy"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(9); } } -- cgit v1.2.3 From dc0b3aed4782e4e4835fd6b9d59d1d70b78be4a7 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 8 May 2024 15:26:00 -0400 Subject: Bump up coroutine stack size: saw C00000FD test termination. --- indra/llcommon/llcoros.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c13900f74a..8612f9353f 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -123,7 +123,7 @@ LLCoros::LLCoros(): // Previously we used // boost::context::guarded_stack_allocator::default_stacksize(); // empirically this is insufficient. - mStackSize(900*1024), + mStackSize(1024*1024), // mCurrent does NOT own the current CoroData instance -- it simply // points to it. So initialize it with a no-op deleter. mCurrent{ [](CoroData*){} } -- cgit v1.2.3 From 81818b94ae0a4997a7f2f09d270536b0d9ba5ea0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 8 May 2024 16:53:29 -0400 Subject: On mathmisc_test failure with random values, report values. --- indra/llmath/tests/mathmisc_test.cpp | 56 ++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp index f12140cf8f..cecb8b2edb 100644 --- a/indra/llmath/tests/mathmisc_test.cpp +++ b/indra/llmath/tests/mathmisc_test.cpp @@ -648,15 +648,15 @@ namespace tut LLVector3 direction = x_line.getDirection(); ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f - && 0.f == direction.mV[VY] - && 0.f == direction.mV[VZ] ); + && 0.f == direction.mV[VY] + && 0.f == direction.mV[VZ] ); direction = y_line.getDirection(); ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] && fabs(direction.mV[VY]) == 1.f - && 0.f == direction.mV[VZ] ); + && 0.f == direction.mV[VZ] ); direction = z_line.getDirection(); ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] - && 0.f == direction.mV[VY] + && 0.f == direction.mV[VY] && fabs(direction.mV[VZ]) == 1.f ); // next some random tests @@ -666,21 +666,21 @@ namespace tut { // generate the known line LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); some_point.normalize(); some_point *= ll_frand(LARGE_RADIUS); LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); another_point.normalize(); another_point *= ll_frand(LARGE_RADIUS); LLLine known_intersection(some_point, another_point); // compute a plane that intersect the line LLVector3 point_on_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); point_on_plane.normalize(); point_on_plane *= ll_frand(LARGE_RADIUS); LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); @@ -689,8 +689,8 @@ namespace tut // compute a different plane that intersect the line LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); point_on_different_plane.normalize(); point_on_different_plane *= ll_frand(LARGE_RADIUS); LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); @@ -709,14 +709,34 @@ namespace tut first_plane, second_plane); - ensure("plane intersection should succeed", success); + try + { + ensure("plane intersection should succeed", success); - F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); - ensure("measured intersection should be parallel to known intersection", - dot > ALMOST_PARALLEL); + F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); + ensure("measured intersection should be parallel to known intersection", + dot > ALMOST_PARALLEL); - ensure("measured intersection should pass near known point", - measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); + ensure("measured intersection should pass near known point", + measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); + } + catch (const failure&) + { + // If any of these assertions fail, since the values involved + // are randomly generated, unless we report them, we have no + // hope of diagnosing the problem. + LL_INFOS() << "some_point = " << some_point << '\n' + << "another_point = " << another_point << '\n' + << "known_intersection = " << known_intersection << '\n' + << "point_on_plane = " << point_on_plane << '\n' + << "plane_normal = " << plane_normal << '\n' + << "first_plane = " << first_plane << '\n' + << "point_on_different_plane = " << point_on_different_plane << '\n' + << "different_plane_normal = " << different_plane_normal << '\n' + << "second_plane = " << second_plane << '\n' + << "measured_intersection = " << measured_intersection << LL_ENDL; + throw; + } } } } -- cgit v1.2.3 From bd8e1dd8d2340636521200d15a045321ea07b986 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 8 May 2024 16:58:34 -0400 Subject: Tweak a couple things --- indra/llcommon/workqueue.h | 2 +- indra/newview/llappearancemgr.cpp | 4 ++-- indra/newview/scripts/lua/LLDebugSettings.lua | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index b658966f63..ecc6f27223 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -541,7 +541,7 @@ namespace LL reply, // Bind the current exception to transport back to the // originating WorkQueue. Once there, rethrow it. - [exc = std::current_exception()](){ std::rethrow_exception(exc); }); + [exc = std::current_exception()]{ std::rethrow_exception(exc); }); } }, // if caller passed a TimePoint, pass it along to post() diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5b8835add8..dccd63af38 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -618,8 +618,8 @@ void LLBrokenLinkObserver::changed(U32 mask) if (id == mUUID) { // Might not be processed yet and it is not a - // good idea to update appearane here, postpone. - doOnIdleOneTime([this]() + // good idea to update appearance here, postpone. + doOnIdleOneTime([this] { postProcess(); }); diff --git a/indra/newview/scripts/lua/LLDebugSettings.lua b/indra/newview/scripts/lua/LLDebugSettings.lua index c809dfff91..c1d74fe00a 100644 --- a/indra/newview/scripts/lua/LLDebugSettings.lua +++ b/indra/newview/scripts/lua/LLDebugSettings.lua @@ -1,6 +1,6 @@ leap = require 'leap' -function check_response(res) +local function check_response(res) if res.error then error(res.error) end -- cgit v1.2.3 From 5060ccb1530ab576458aeff0d0b2b5dd24bc5880 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 9 May 2024 16:05:46 -0400 Subject: Add "Timers" LLEventAPI, actually a LazyEventAPI, for LL::Timers. Rename LL::Timers::scheduleRepeating() to scheduleEvery(). --- indra/llcommon/llcallbacklist.cpp | 156 ++++++++++++++++++++++++++++++++++++-- indra/llcommon/llcallbacklist.h | 10 +-- indra/llcommon/llevents.cpp | 7 +- indra/llcommon/lleventtimer.cpp | 2 +- 4 files changed, 161 insertions(+), 14 deletions(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 52e9860e02..c89f7d12b2 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -24,8 +24,10 @@ * $/LicenseInfo$ */ +#include "lazyeventapi.h" #include "llcallbacklist.h" #include "llexception.h" +#include "llsdutil.h" #include // @@ -140,22 +142,22 @@ Timers::handle_t Timers::scheduleAt(nullary_func_t callable, LLDate::timestamp t { // tick() assumes you want to run periodically until you return true. // Schedule a task that returns true after a single call. - return scheduleAtRepeating(once(callable), time, 0); + return scheduleAtEvery(once(callable), time, 0); } // Call a given callable once after specified interval. Timers::handle_t Timers::scheduleAfter(nullary_func_t callable, F32 seconds) { - return scheduleRepeating(once(callable), seconds); + return scheduleEvery(once(callable), seconds); } // Call a given callable every specified number of seconds, until it returns true. -Timers::handle_t Timers::scheduleRepeating(bool_func_t callable, F32 seconds) +Timers::handle_t Timers::scheduleEvery(bool_func_t callable, F32 seconds) { - return scheduleAtRepeating(callable, now() + seconds, seconds); + return scheduleAtEvery(callable, now() + seconds, seconds); } -Timers::handle_t Timers::scheduleAtRepeating(bool_func_t callable, +Timers::handle_t Timers::scheduleAtEvery(bool_func_t callable, LLDate::timestamp time, F32 interval) { // Pick token FIRST to store a self-reference in mQueue's managed node as @@ -203,7 +205,7 @@ F32 Timers::timeUntilCall(handle_t timer) const } } -// Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleRepeating() +// Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleEvery() bool Timers::cancel(handle_t& timer) { // For exception safety, capture and clear timer before canceling. @@ -383,4 +385,146 @@ bool Timers::tick() return mQueue.empty(); } +/***************************************************************************** +* TimersListener +*****************************************************************************/ + +class TimersListener: public LLEventAPI +{ +public: + TimersListener(const LazyEventAPIParams& params): LLEventAPI(params) {} + + // Forbid a script from requesting callbacks too quickly. + static constexpr LLSD::Real MINTIMER{ 1.0 }; + + void scheduleAfter(const LLSD& params); + void scheduleEvery(const LLSD& params); + LLSD cancel(const LLSD& params); + LLSD isRunning(const LLSD& params); + LLSD timeUntilCall(const LLSD& params); + +private: + using HandleMap = std::unordered_map; + HandleMap mHandles; +}; + +void TimersListener::scheduleAfter(const LLSD& params) +{ + LLSD::Real after{ params["after"] }; + if (after < MINTIMER) + { + sendReply(llsd::map("error", stringize("after must be at least ", MINTIMER)), params); + return; + } + + mHandles.emplace( + params["reqid"], + Timers::instance().scheduleAfter( + [this, params] + { + // we don't need any content save for the "reqid" + sendReply({}, params); + // ditch mHandles entry + mHandles.erase(params["reqid"]); + }, + after)); +} + +void TimersListener::scheduleEvery(const LLSD& params) +{ + LLSD::Real every{ params["every"] }; + if (every < MINTIMER) + { + sendReply(llsd::map("error", stringize("every must be at least ", MINTIMER)), params); + return; + } + + mHandles.emplace( + params["reqid"], + Timers::instance().scheduleEvery( + [params, i=0]() mutable + { + // we don't need any content save for the "reqid" + sendReply(llsd::map("i", i++), params); + // we can't use a handshake -- always keep the ball rolling + return false; + }, + every)); +} + +LLSD TimersListener::cancel(const LLSD& params) +{ + auto found{ mHandles.find(params["id"]) }; + bool ok = false; + if (found != mHandles.end()) + { + ok = true; + Timers::instance().cancel(found->second); + mHandles.erase(found); + } + return llsd::map("ok", ok); +} + +LLSD TimersListener::isRunning(const LLSD& params) +{ + auto found{ mHandles.find(params["id"]) }; + bool running = false; + if (found != mHandles.end()) + { + running = Timers::instance().isRunning(found->second); + } + return llsd::map("running", running); +} + +LLSD TimersListener::timeUntilCall(const LLSD& params) +{ + auto found{ mHandles.find(params["id"]) }; + bool ok = false; + LLSD::Real remaining = 0; + if (found != mHandles.end()) + { + ok = true; + remaining = Timers::instance().timeUntilCall(found->second); + } + return llsd::map("ok", ok, "remaining", remaining); +} + +class TimersRegistrar: public LazyEventAPI +{ + using super = LazyEventAPI; + using super::listener; + +public: + TimersRegistrar(): + super("Timers", "Provide access to viewer timer functionality.") + { + add("scheduleAfter", +R"-(Create a timer with ID "reqid". Post response after "after" seconds.)-", + &listener::scheduleAfter, + llsd::map("reqid", LLSD::Integer(), "after", LLSD::Real())); + add("scheduleEvery", +R"-(Create a timer with ID "reqid". Post response every "every" seconds +until cancel().)-", + &listener::scheduleEvery, + llsd::map("reqid", LLSD::Integer(), "every", LLSD::Real())); + add("cancel", +R"-(Cancel the timer with ID "id". Respond "ok"=true if "id" identifies +a live timer.)-", + &listener::cancel, + llsd::map("reqid", LLSD::Integer(), "id", LLSD::Integer())); + add("isRunning", +R"-(Query the timer with ID "id": respond "running"=true if "id" identifies +a live timer.)-", + &listener::isRunning, + llsd::map("reqid", LLSD::Integer(), "id", LLSD::Integer())); + add("timeUntilCall", +R"-(Query the timer with ID "id": if "id" identifies a live timer, respond +"ok"=true, "remaining"=seconds with the time left before timer expiry; +otherwise "ok"=false, "remaining"=0.)-", + &listener::timeUntilCall, + llsd::map("reqid", LLSD::Integer())); + } +}; +static TimersRegistrar registrar; + } // namespace LL diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index f9b15867ef..2fb27d5ea8 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -168,14 +168,14 @@ public: handle_t scheduleAfter(nullary_func_t callable, F32 seconds); // Call a given callable every specified number of seconds, until it returns true. - handle_t scheduleRepeating(bool_func_t callable, F32 seconds); + handle_t scheduleEvery(bool_func_t callable, F32 seconds); // test whether specified handle is still live bool isRunning(handle_t timer) const; // check remaining time F32 timeUntilCall(handle_t timer) const; - // Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleRepeating(). + // Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleEvery(). // Return true if and only if the handle corresponds to a live timer. bool cancel(const handle_t& timer); // If we're canceling a non-const handle_t, also clear it so we need not @@ -183,7 +183,7 @@ public: bool cancel(handle_t& timer); // Store a handle_t returned by scheduleAt(), scheduleAfter() or - // scheduleRepeating() in a temp_handle_t to cancel() automatically on + // scheduleEvery() in a temp_handle_t to cancel() automatically on // destruction of the temp_handle_t. class temp_handle_t { @@ -237,7 +237,7 @@ public: }; private: - handle_t scheduleAtRepeating(bool_func_t callable, LLDate::timestamp time, F32 interval); + handle_t scheduleAtEvery(bool_func_t callable, LLDate::timestamp time, F32 interval); LLDate::timestamp now() const { return LLDate::now().secondsSinceEpoch(); } // wrap a nullary_func_t with a bool_func_t that will only execute once bool_func_t once(nullary_func_t callable) @@ -294,7 +294,7 @@ LL::Timers::handle_t doAfterInterval(nullary_func_t callable, F32 seconds) inline LL::Timers::handle_t doPeriodically(bool_func_t callable, F32 seconds) { - return LL::Timers::instance().scheduleRepeating(callable, seconds); + return LL::Timers::instance().scheduleEvery(callable, seconds); } #endif diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index d7870763cc..e10e555f8b 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -759,6 +759,9 @@ bool sendReply(LLSD reply, const LLSD& request, const std::string& replyKey) LLReqID reqID(request); // and copy it to 'reply'. reqID.stamp(reply); - // Send reply on LLEventPump named in request[replyKey]. - return LLEventPumps::instance().obtain(request[replyKey]).post(reply); + // Send reply on LLEventPump named in request[replyKey] -- if that + // LLEventPump exists. If it does not, don't create it. + // This addresses the case in which a requester goes away before a + // particular LLEventAPI responds. + return LLEventPumps::instance().post(request[replyKey], reply); } diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index 1d2da93683..43c1a255ac 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -49,7 +49,7 @@ LLEventTimer::~LLEventTimer() void LLEventTimer::start() { - mTimer = LL::Timers::instance().scheduleRepeating([this]{ return tick(); }, mPeriod); + mTimer = LL::Timers::instance().scheduleEvery([this]{ return tick(); }, mPeriod); } void LLEventTimer::stop() -- cgit v1.2.3 From 271bc05b91772e5aedd834db116734b34f0108a1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 10 May 2024 09:55:19 -0400 Subject: Fix latent access violation in ~LLEventPump() if LLEventPumps gone. Instead of making LLEventPumps an LLHandleProvider, and storing an LLHandle in each LLEventPump instance, just make ~LLEventPump() query LLEventPumps::instanceExists() before calling instance(). --- indra/llcommon/llevents.cpp | 8 +++----- indra/llcommon/llevents.h | 16 +--------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index e10e555f8b..5a6e13cb7d 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -359,8 +359,7 @@ const std::string LLEventPump::ANONYMOUS = std::string(); LLEventPump::LLEventPump(const std::string& name, bool tweak): // Register every new instance with LLEventPumps - mRegistry(LLEventPumps::instance().getHandle()), - mName(mRegistry.get()->registerNew(*this, name, tweak)), + mName(LLEventPumps::instance().registerNew(*this, name, tweak)), mSignal(std::make_shared()), mEnabled(true) {} @@ -373,10 +372,9 @@ LLEventPump::~LLEventPump() { // Unregister this doomed instance from LLEventPumps -- but only if // LLEventPumps is still around! - LLEventPumps* registry = mRegistry.get(); - if (registry) + if (LLEventPumps::instanceExists()) { - registry->unregister(*this); + LLEventPumps::instance().unregister(*this); } } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 1fc0f23ecd..15d1d5035c 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -53,7 +53,6 @@ #include "llsingleton.h" #include "lldependencies.h" #include "llexception.h" -#include "llhandle.h" // hack for testing #ifndef testable @@ -213,15 +212,7 @@ class LLEventPump; * LLEventPumps is a Singleton manager through which one typically accesses * this subsystem. */ -// LLEventPumps isa LLHandleProvider only for (hopefully rare) long-lived -// class objects that must refer to this class late in their lifespan, say in -// the destructor. Specifically, the case that matters is a possible reference -// after LLEventPumps::deleteSingleton(). (Lingering LLEventPump instances are -// capable of this.) In that case, instead of calling LLEventPumps::instance() -// again -- resurrecting the deleted LLSingleton -- store an -// LLHandle and test it before use. -class LL_COMMON_API LLEventPumps: public LLSingleton, - public LLHandleProvider +class LL_COMMON_API LLEventPumps: public LLSingleton { LLSINGLETON(LLEventPumps); public: @@ -582,12 +573,7 @@ private: virtual void clear(); virtual void reset(); - - private: - // must precede mName; see LLEventPump::LLEventPump() - LLHandle mRegistry; - std::string mName; LLMutex mConnectionListMutex; -- cgit v1.2.3 From 2c687e6d687ead0f29c096271b207dbe16b31c35 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 10 May 2024 11:05:56 -0400 Subject: Fix up a few #includes --- indra/llcommon/lldependencies.h | 3 ++- indra/llcommon/llevents.h | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index 950af4a4ad..e225119dfb 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -30,6 +30,8 @@ #if ! defined(LL_LLDEPENDENCIES_H) #define LL_LLDEPENDENCIES_H +#include "linden_common.h" +#include "llexception.h" #include #include #include @@ -40,7 +42,6 @@ #include #include #include -#include "llexception.h" /***************************************************************************** * Utilities diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 15d1d5035c..2cc1f91408 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -49,10 +49,11 @@ #endif #include -#include "llsd.h" -#include "llsingleton.h" #include "lldependencies.h" #include "llexception.h" +#include "llmutex.h" +#include "llsd.h" +#include "llsingleton.h" // hack for testing #ifndef testable -- cgit v1.2.3 From 1abf5f18d6afc7ae9e1b1562b92e5c1ce33b722f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 09:03:02 -0400 Subject: Make leap.lua honor an "error" key in viewer response. --- indra/newview/scripts/lua/leap.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index ade91789f0..cfb7377523 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -161,10 +161,12 @@ function leap.request(pump, data) dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response) -- kill off temporary WaitForReqid object, even if error pending[reqid] = nil - if ok then - return response - else + if not ok then error(response) + elseif response.error then + error(response.error) + else + return response end end @@ -186,7 +188,7 @@ function leap.generate(pump, data, checklast) local ok, response, resumed_with repeat ok, response = pcall(waitfor.wait, waitfor) - if not ok then + if (not ok) or response.error then break end -- can resume(false) to terminate generate() and clean up @@ -196,6 +198,8 @@ function leap.generate(pump, data, checklast) pending[reqid] = nil if not ok then error(response) + elseif response.error then + error(response.error) end end -- cgit v1.2.3 From 7137647e90d8c11197513f542f04fb39b483d663 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 12:19:54 -0400 Subject: Manual whitespace cleanup (fix_whitespace.py). --- indra/llcommon/llapp.cpp | 960 +- indra/llcommon/llcallbacklist.cpp | 68 +- indra/llcommon/llcallbacklist.h | 68 +- indra/llcommon/lldate.cpp | 394 +- indra/llcommon/lldate.h | 196 +- indra/llcommon/lldependencies.h | 16 +- indra/llcommon/llerror.cpp | 1724 +-- indra/llcommon/llevents.h | 42 +- indra/llcommon/lleventtimer.cpp | 14 +- indra/llcommon/lleventtimer.h | 36 +- indra/llcommon/lllivefile.cpp | 152 +- indra/llcommon/llrefcount.h | 156 +- indra/llcommon/llrun.h | 204 +- indra/llcommon/llstring.h | 2452 ++-- indra/llcommon/tests/llerror_test.cpp | 1432 +-- indra/llcommon/tests/llsdserialize_test.cpp | 3048 ++--- indra/llfilesystem/lldir.cpp | 1494 +-- indra/llfilesystem/lldir.h | 420 +- indra/llmath/tests/mathmisc_test.cpp | 1368 +-- indra/llmessage/llcoproceduremanager.cpp | 20 +- indra/llui/llflashtimer.cpp | 72 +- indra/llui/llflashtimer.h | 58 +- indra/llui/llmenugl.h | 1248 +- indra/llui/lltexteditor.cpp | 4634 +++---- indra/llui/lltexteditor.h | 456 +- indra/llwindow/llwindow.h | 370 +- indra/llwindow/llwindowmacosx-objc.h | 16 +- indra/llwindow/llwindowmacosx.cpp | 2574 ++-- indra/llwindow/llwindowmacosx.h | 334 +- indra/llwindow/llwindowwin32.cpp | 4130 +++---- indra/llwindow/llwindowwin32.h | 364 +- indra/llxml/llcontrol.cpp | 1830 +-- indra/llxml/llcontrol.h | 614 +- indra/newview/llappearancemgr.cpp | 6168 +++++----- indra/newview/llappviewer.cpp | 7034 +++++------ .../newview/lldonotdisturbnotificationstorage.cpp | 214 +- indra/newview/lldonotdisturbnotificationstorage.h | 16 +- indra/newview/llfilepicker.cpp | 2080 ++-- indra/newview/llfilepicker.h | 206 +- indra/newview/llfloaterlinkreplace.cpp | 618 +- indra/newview/llfloaterlinkreplace.h | 136 +- indra/newview/llfloaterluadebug.cpp | 36 +- indra/newview/llfloaterpreference.cpp | 3284 ++--- indra/newview/llfloaterregionrestarting.cpp | 196 +- indra/newview/llfloaterregionrestarting.h | 58 +- indra/newview/llfloatersettingsdebug.cpp | 706 +- indra/newview/llfloatersettingsdebug.h | 38 +- indra/newview/llfloateruipreview.cpp | 2664 ++-- indra/newview/llimview.cpp | 5100 ++++---- indra/newview/llimview.h | 890 +- indra/newview/llinventoryfunctions.cpp | 1964 +-- indra/newview/llinventoryfunctions.h | 282 +- indra/newview/llinventorymodel.cpp | 6722 +++++----- indra/newview/lllocalbitmaps.cpp | 1646 +-- indra/newview/lllocalbitmaps.h | 160 +- indra/newview/lllocalgltfmaterials.h | 20 +- indra/newview/llmediadataclient.cpp | 980 +- indra/newview/llmediadataclient.h | 514 +- indra/newview/llpanelpeople.cpp | 2280 ++-- indra/newview/llsetkeybinddialog.cpp | 16 +- indra/newview/llspeakers.cpp | 1322 +- indra/newview/llspeakers.h | 430 +- indra/newview/llstartup.cpp | 6120 +++++----- indra/newview/lltoast.cpp | 762 +- indra/newview/lltoast.h | 284 +- indra/newview/lltoolplacer.cpp | 872 +- indra/newview/lltoolplacer.h | 36 +- indra/newview/llviewercontrollistener.cpp | 292 +- indra/newview/llviewerfloaterreg.cpp | 418 +- indra/newview/llviewermenu.cpp | 12102 +++++++++---------- indra/newview/llviewermenu.h | 56 +- indra/newview/llviewermenufile.cpp | 1408 +-- indra/newview/llviewermenufile.h | 76 +- indra/newview/llviewermessage.cpp | 10706 ++++++++-------- indra/newview/llviewerparcelmediaautoplay.cpp | 208 +- indra/newview/llviewerparcelmediaautoplay.h | 24 +- indra/test/io.cpp | 2232 ++-- indra/test/lltut.h | 188 +- 78 files changed, 56264 insertions(+), 56264 deletions(-) diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 5722f10f62..852859598b 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llapp.cpp * @brief Implementation of the LLApp class. * * $LicenseInfo:firstyear=2003&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$ */ @@ -70,8 +70,8 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *); #else // Called by breakpad exception handler after the minidump has been generated. bool unix_post_minidump_callback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); + const char *minidump_id, + void *context, bool succeeded); #endif # if LL_DARWIN @@ -94,7 +94,7 @@ LLApp* LLApp::sApplication = NULL; // Allows the generation of core files for post mortem under gdb // and disables crashlogger -BOOL LLApp::sDisableCrashlogger = FALSE; +BOOL LLApp::sDisableCrashlogger = FALSE; // Local flag for whether or not to do logging in signal handlers. //static @@ -108,222 +108,222 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL; LLApp::LLApp() { - // Set our status to running - setStatus(APP_STATUS_RUNNING); + // Set our status to running + setStatus(APP_STATUS_RUNNING); + + LLCommon::initClass(); - LLCommon::initClass(); + // initialize the options structure. We need to make this an array + // because the structured data will not auto-allocate if we + // reference an invalid location with the [] operator. + mOptions = LLSD::emptyArray(); + LLSD sd; + for(int i = 0; i < PRIORITY_COUNT; ++i) + { + mOptions.append(sd); + } - // initialize the options structure. We need to make this an array - // because the structured data will not auto-allocate if we - // reference an invalid location with the [] operator. - mOptions = LLSD::emptyArray(); - LLSD sd; - for(int i = 0; i < PRIORITY_COUNT; ++i) - { - mOptions.append(sd); - } + // Make sure we clean up APR when we exit + // Don't need to do this if we're cleaning up APR in the destructor + //atexit(ll_cleanup_apr); - // Make sure we clean up APR when we exit - // Don't need to do this if we're cleaning up APR in the destructor - //atexit(ll_cleanup_apr); + // Set the application to this instance. + sApplication = this; - // Set the application to this instance. - sApplication = this; - - // initialize the buffer to write the minidump filename to - // (this is used to avoid allocating memory in the crash handler) - memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); - mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; + // initialize the buffer to write the minidump filename to + // (this is used to avoid allocating memory in the crash handler) + memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::~LLApp() { - // reclaim live file memory - std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); - mLiveFiles.clear(); + // reclaim live file memory + std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); + mLiveFiles.clear(); - setStopped(); + setStopped(); - SUBSYSTEM_CLEANUP_DBG(LLCommon); + SUBSYSTEM_CLEANUP_DBG(LLCommon); } // static LLApp* LLApp::instance() { - return sApplication; + return sApplication; } LLSD LLApp::getOption(const std::string& name) const { - LLSD rv; - LLSD::array_const_iterator iter = mOptions.beginArray(); - LLSD::array_const_iterator end = mOptions.endArray(); - for(; iter != end; ++iter) - { - rv = (*iter)[name]; - if(rv.isDefined()) break; - } - return rv; + LLSD rv; + LLSD::array_const_iterator iter = mOptions.beginArray(); + LLSD::array_const_iterator end = mOptions.endArray(); + for(; iter != end; ++iter) + { + rv = (*iter)[name]; + if(rv.isDefined()) break; + } + return rv; } bool LLApp::parseCommandOptions(int argc, char** argv) { - LLSD commands; - std::string name; - std::string value; - for(int ii = 1; ii < argc; ++ii) - { - if(argv[ii][0] != '-') - { - LL_INFOS() << "Did not find option identifier while parsing token: " - << argv[ii] << LL_ENDL; - return false; - } - int offset = 1; - if(argv[ii][1] == '-') ++offset; - name.assign(&argv[ii][offset]); - if(((ii+1) >= argc) || (argv[ii+1][0] == '-')) - { - // we found another option after this one or we have - // reached the end. simply record that this option was - // found and continue. - int flag = name.compare("logfile"); - if (0 == flag) - { - commands[name] = "log"; - } - else - { - commands[name] = true; - } - - continue; - } - ++ii; - value.assign(argv[ii]); + LLSD commands; + std::string name; + std::string value; + for(int ii = 1; ii < argc; ++ii) + { + if(argv[ii][0] != '-') + { + LL_INFOS() << "Did not find option identifier while parsing token: " + << argv[ii] << LL_ENDL; + return false; + } + int offset = 1; + if(argv[ii][1] == '-') ++offset; + name.assign(&argv[ii][offset]); + if(((ii+1) >= argc) || (argv[ii+1][0] == '-')) + { + // we found another option after this one or we have + // reached the end. simply record that this option was + // found and continue. + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + + continue; + } + ++ii; + value.assign(argv[ii]); #if LL_WINDOWS - //Windows changed command line parsing. Deal with it. - S32 slen = value.length() - 1; - S32 start = 0; - S32 end = slen; - if (argv[ii][start]=='"')start++; - if (argv[ii][end]=='"')end--; - if (start!=0 || end!=slen) - { - value = value.substr (start,end); - } + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } #endif - commands[name] = value; - } - setOptionData(PRIORITY_COMMAND_LINE, commands); - return true; + commands[name] = value; + } + setOptionData(PRIORITY_COMMAND_LINE, commands); + return true; } bool LLApp::parseCommandOptions(int argc, wchar_t** wargv) { - LLSD commands; - std::string name; - std::string value; - for(int ii = 1; ii < argc; ++ii) - { - if(wargv[ii][0] != '-') - { - LL_INFOS() << "Did not find option identifier while parsing token: " - << wargv[ii] << LL_ENDL; - return false; - } - int offset = 1; - if(wargv[ii][1] == '-') ++offset; + LLSD commands; + std::string name; + std::string value; + for(int ii = 1; ii < argc; ++ii) + { + if(wargv[ii][0] != '-') + { + LL_INFOS() << "Did not find option identifier while parsing token: " + << wargv[ii] << LL_ENDL; + return false; + } + int offset = 1; + if(wargv[ii][1] == '-') ++offset; #if LL_WINDOWS - name.assign(utf16str_to_utf8str(&wargv[ii][offset])); + name.assign(utf16str_to_utf8str(&wargv[ii][offset])); #else - name.assign(wstring_to_utf8str(&wargv[ii][offset])); + name.assign(wstring_to_utf8str(&wargv[ii][offset])); #endif - if(((ii+1) >= argc) || (wargv[ii+1][0] == '-')) - { - // we found another option after this one or we have - // reached the end. simply record that this option was - // found and continue. - int flag = name.compare("logfile"); - if (0 == flag) - { - commands[name] = "log"; - } - else - { - commands[name] = true; - } - - continue; - } - ++ii; + if(((ii+1) >= argc) || (wargv[ii+1][0] == '-')) + { + // we found another option after this one or we have + // reached the end. simply record that this option was + // found and continue. + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + + continue; + } + ++ii; #if LL_WINDOWS - value.assign(utf16str_to_utf8str((wargv[ii]))); + value.assign(utf16str_to_utf8str((wargv[ii]))); #else - value.assign(wstring_to_utf8str((wargv[ii]))); + value.assign(wstring_to_utf8str((wargv[ii]))); #endif #if LL_WINDOWS - //Windows changed command line parsing. Deal with it. - S32 slen = value.length() - 1; - S32 start = 0; - S32 end = slen; - if (wargv[ii][start]=='"')start++; - if (wargv[ii][end]=='"')end--; - if (start!=0 || end!=slen) - { - value = value.substr (start,end); - } + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (wargv[ii][start]=='"')start++; + if (wargv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } #endif - commands[name] = value; - } - setOptionData(PRIORITY_COMMAND_LINE, commands); - return true; + commands[name] = value; + } + setOptionData(PRIORITY_COMMAND_LINE, commands); + return true; } void LLApp::manageLiveFile(LLLiveFile* livefile) { - if(!livefile) return; - livefile->checkAndReload(); - livefile->addToEventTimer(); - mLiveFiles.push_back(livefile); + if(!livefile) return; + livefile->checkAndReload(); + livefile->addToEventTimer(); + mLiveFiles.push_back(livefile); } bool LLApp::setOptionData(OptionPriority level, LLSD data) { - if((level < 0) - || (level >= PRIORITY_COUNT) - || (data.type() != LLSD::TypeMap)) - { - return false; - } - mOptions[level] = data; - return true; + if((level < 0) + || (level >= PRIORITY_COUNT) + || (data.type() != LLSD::TypeMap)) + { + return false; + } + mOptions[level] = data; + return true; } LLSD LLApp::getOptionData(OptionPriority level) { - if((level < 0) || (level >= PRIORITY_COUNT)) - { - return LLSD(); - } - return mOptions[level]; + if((level < 0) || (level >= PRIORITY_COUNT)) + { + return LLSD(); + } + return mOptions[level]; } void LLApp::stepFrame() { - LLFrameTimer::updateFrameTime(); - LLFrameTimer::updateFrameCount(); - LLCallbackList::instance().callFunctions(); - mRunner.run(); + LLFrameTimer::updateFrameTime(); + LLFrameTimer::updateFrameCount(); + LLCallbackList::instance().callFunctions(); + mRunner.run(); } #if LL_WINDOWS @@ -332,31 +332,31 @@ void LLApp::stepFrame() //in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/ void EnableCrashingOnCrashes() { - typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); - typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); - const DWORD EXCEPTION_SWALLOWING = 0x1; - - HMODULE kernel32 = LoadLibraryA("kernel32.dll"); - tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, - "GetProcessUserModeExceptionPolicy"); - tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, - "SetProcessUserModeExceptionPolicy"); - if (pGetPolicy && pSetPolicy) - { - DWORD dwFlags; - if (pGetPolicy(&dwFlags)) - { - // Turn off the filter - pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); - } - } + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) + { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) + { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } } #endif void LLApp::setupErrorHandling(bool second_instance) { - // Error handling is done by starting up an error handling thread, which just sleeps and - // occasionally checks to see if the app is in an error state, and sees if it needs to be run. + // Error handling is done by starting up an error handling thread, which just sleeps and + // occasionally checks to see if the app is in an error state, and sees if it needs to be run. #if LL_WINDOWS @@ -377,19 +377,19 @@ void LLApp::setupErrorHandling(bool second_instance) void LLApp::setErrorHandler(LLAppErrorHandler handler) { - LLApp::sErrorHandler = handler; + LLApp::sErrorHandler = handler; } // static void LLApp::runErrorHandler() { - if (LLApp::sErrorHandler) - { - LLApp::sErrorHandler(); - } + if (LLApp::sErrorHandler) + { + LLApp::sErrorHandler(); + } - //LL_INFOS() << "App status now STOPPED" << LL_ENDL; - LLApp::setStopped(); + //LL_INFOS() << "App status now STOPPED" << LL_ENDL; + LLApp::setStopped(); } namespace @@ -435,14 +435,14 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - // set app status to ERROR - setStatus(APP_STATUS_ERROR); + // set app status to ERROR + setStatus(APP_STATUS_ERROR); } void LLApp::setDebugFileNames(const std::string &path) { - mStaticDebugFileName = path + "static_debug_info.log"; - mDynamicDebugFileName = path + "dynamic_debug_info.log"; + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; } void LLApp::writeMiniDump() @@ -452,64 +452,64 @@ void LLApp::writeMiniDump() // static void LLApp::setQuitting() { - if (!isExiting()) - { - // If we're already exiting, we don't want to reset our state back to quitting. - LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; - setStatus(APP_STATUS_QUITTING); - } + if (!isExiting()) + { + // If we're already exiting, we don't want to reset our state back to quitting. + LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; + setStatus(APP_STATUS_QUITTING); + } } // static void LLApp::setStopped() { - setStatus(APP_STATUS_STOPPED); + setStatus(APP_STATUS_STOPPED); } // static bool LLApp::isStopped() { - return (APP_STATUS_STOPPED == sStatus.get()); + return (APP_STATUS_STOPPED == sStatus.get()); } // static bool LLApp::isRunning() { - return (APP_STATUS_RUNNING == sStatus.get()); + return (APP_STATUS_RUNNING == sStatus.get()); } // static bool LLApp::isError() { - return (APP_STATUS_ERROR == sStatus.get()); + return (APP_STATUS_ERROR == sStatus.get()); } // static bool LLApp::isQuitting() { - return (APP_STATUS_QUITTING == sStatus.get()); + return (APP_STATUS_QUITTING == sStatus.get()); } // static bool LLApp::isExiting() { - return isQuitting() || isError(); + return isQuitting() || isError(); } void LLApp::disableCrashlogger() { - sDisableCrashlogger = TRUE; + sDisableCrashlogger = TRUE; } // static bool LLApp::isCrashloggerDisabled() { - return (sDisableCrashlogger == TRUE); + return (sDisableCrashlogger == TRUE); } // static @@ -518,336 +518,336 @@ int LLApp::getPid() #if LL_WINDOWS return GetCurrentProcessId(); #else - return getpid(); + return getpid(); #endif } #if LL_WINDOWS LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop) { - // Translate the signals/exceptions into cross-platform stuff - // Windows implementation + // Translate the signals/exceptions into cross-platform stuff + // Windows implementation - // Make sure the user sees something to indicate that the app crashed. - LONG retval; + // Make sure the user sees something to indicate that the app crashed. + LONG retval; - if (LLApp::isError()) - { - LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; - } + if (LLApp::isError()) + { + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; + retval = EXCEPTION_EXECUTE_HANDLER; + return retval; + } - // Flag status to error, so thread_error starts its work - LLApp::setError(); + // Flag status to error, so thread_error starts its work + LLApp::setError(); - // Block in the exception handler until the app has stopped - // This is pretty sketchy, but appears to work just fine - while (!LLApp::isStopped()) - { - ms_sleep(10); - } + // Block in the exception handler until the app has stopped + // This is pretty sketchy, but appears to work just fine + while (!LLApp::isStopped()) + { + ms_sleep(10); + } - // - // Generate a minidump if we can. - // - // TODO: This needs to be ported over form the viewer-specific - // LLWinDebug class + // + // Generate a minidump if we can. + // + // TODO: This needs to be ported over form the viewer-specific + // LLWinDebug class - // - // At this point, we always want to exit the app. There's no graceful - // recovery for an unhandled exception. - // - // Just kill the process. - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; + // + // At this point, we always want to exit the app. There's no graceful + // recovery for an unhandled exception. + // + // Just kill the process. + retval = EXCEPTION_EXECUTE_HANDLER; + return retval; } // Win32 doesn't support signals. This is used instead. -BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) -{ - switch (fdwCtrlType) - { - case CTRL_BREAK_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - case CTRL_CLOSE_EVENT: // From end task or the window close button. - case CTRL_C_EVENT: // from CTRL-C on the keyboard - // Just set our state to quitting, not error - if (LLApp::isQuitting() || LLApp::isError()) - { - // We're already trying to die, just ignore this signal - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; - } - return TRUE; - } - LLApp::setQuitting(); - return TRUE; - - default: - return FALSE; - } -} +BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + case CTRL_CLOSE_EVENT: // From end task or the window close button. + case CTRL_C_EVENT: // from CTRL-C on the keyboard + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; + } + return TRUE; + } + LLApp::setQuitting(); + return TRUE; + + default: + return FALSE; + } +} #else //!LL_WINDOWS void setup_signals() { - // - // Set up signal handlers that may result in program termination - // - struct sigaction act; - act.sa_sigaction = default_unix_signal_handler; - sigemptyset( &act.sa_mask ); - act.sa_flags = SA_SIGINFO; + // + // Set up signal handlers that may result in program termination + // + struct sigaction act; + act.sa_sigaction = default_unix_signal_handler; + sigemptyset( &act.sa_mask ); + act.sa_flags = SA_SIGINFO; - // Synchronous signals + // Synchronous signals # ifndef LL_BUGSPLAT - sigaction(SIGABRT, &act, NULL); + sigaction(SIGABRT, &act, NULL); # endif - sigaction(SIGALRM, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGPIPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSYS, &act, NULL); - - sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); - sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); - - // Asynchronous signals that are normally ignored + sigaction(SIGALRM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSYS, &act, NULL); + + sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); + sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); + + // Asynchronous signals that are normally ignored #ifndef LL_IGNORE_SIGCHLD - sigaction(SIGCHLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); #endif // LL_IGNORE_SIGCHLD - sigaction(SIGUSR2, &act, NULL); + sigaction(SIGUSR2, &act, NULL); - // Asynchronous signals that result in attempted graceful exit - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGINT, &act, NULL); + // Asynchronous signals that result in attempted graceful exit + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); + + // Asynchronous signals that result in core + sigaction(SIGQUIT, &act, NULL); - // Asynchronous signals that result in core - sigaction(SIGQUIT, &act, NULL); - } void clear_signals() { - struct sigaction act; - act.sa_handler = SIG_DFL; - sigemptyset( &act.sa_mask ); - act.sa_flags = SA_SIGINFO; + struct sigaction act; + act.sa_handler = SIG_DFL; + sigemptyset( &act.sa_mask ); + act.sa_flags = SA_SIGINFO; - // Synchronous signals + // Synchronous signals # ifndef LL_BUGSPLAT - sigaction(SIGABRT, &act, NULL); + sigaction(SIGABRT, &act, NULL); # endif - sigaction(SIGALRM, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGPIPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSYS, &act, NULL); - - sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); - sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); - - // Asynchronous signals that are normally ignored + sigaction(SIGALRM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSYS, &act, NULL); + + sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); + sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); + + // Asynchronous signals that are normally ignored #ifndef LL_IGNORE_SIGCHLD - sigaction(SIGCHLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); #endif // LL_IGNORE_SIGCHLD - // Asynchronous signals that result in attempted graceful exit - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGINT, &act, NULL); + // Asynchronous signals that result in attempted graceful exit + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); - // Asynchronous signals that result in core - sigaction(SIGUSR2, &act, NULL); - sigaction(SIGQUIT, &act, NULL); + // Asynchronous signals that result in core + sigaction(SIGUSR2, &act, NULL); + sigaction(SIGQUIT, &act, NULL); } void default_unix_signal_handler(int signum, siginfo_t *info, void *) { - // Unix implementation of synchronous signal handler - // This runs in the thread that threw the signal. - // We do the somewhat sketchy operation of blocking in here until the error handler - // has gracefully stopped the app. + // Unix implementation of synchronous signal handler + // This runs in the thread that threw the signal. + // We do the somewhat sketchy operation of blocking in here until the error handler + // has gracefully stopped the app. - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; - } + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; + } - switch (signum) - { - case SIGCHLD: - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; - } + switch (signum) + { + case SIGCHLD: + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; + } - return; - case SIGABRT: + return; + case SIGABRT: // Note that this handler is not set for SIGABRT when using Bugsplat - // Abort just results in termination of the app, no funky error handling. - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; - } - clear_signals(); - raise(signum); - return; - case SIGINT: - case SIGHUP: - case SIGTERM: - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; - } - // Graceful exit - // Just set our state to quitting, not error - if (LLApp::isQuitting() || LLApp::isError()) - { - // We're already trying to die, just ignore this signal - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; - } - return; - } - LLApp::setQuitting(); - return; - case SIGALRM: - case SIGPIPE: - case SIGUSR2: - default: - if (signum == LL_SMACKDOWN_SIGNAL || - signum == SIGBUS || - signum == SIGILL || - signum == SIGFPE || - signum == SIGSEGV || - signum == SIGQUIT) - { - if (signum == LL_SMACKDOWN_SIGNAL) - { - // Smackdown treated just like any other app termination, for now - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; - } - else - { - // Don't log anything, even errors - this is because this signal could happen anywhere. - LLError::setDefaultLevel(LLError::LEVEL_NONE); - } - - // Change the signal that we reraise to SIGABRT, so we generate a core dump. - signum = SIGABRT; - } - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; - } - if (LLApp::isError()) - { - // Received second fatal signal while handling first, just die right now - // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. - clear_signals(); - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; - } - raise(signum); - return; - } - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; - } - - if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem - { - clear_signals(); - LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; - raise(signum); - return; - } - - // Flag status to ERROR - LLApp::setError(); - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; - } - clear_signals(); - raise(signum); - return; - } else { - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; - } - } - } + // Abort just results in termination of the app, no funky error handling. + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; + } + clear_signals(); + raise(signum); + return; + case SIGINT: + case SIGHUP: + case SIGTERM: + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; + } + // Graceful exit + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; + } + return; + } + LLApp::setQuitting(); + return; + case SIGALRM: + case SIGPIPE: + case SIGUSR2: + default: + if (signum == LL_SMACKDOWN_SIGNAL || + signum == SIGBUS || + signum == SIGILL || + signum == SIGFPE || + signum == SIGSEGV || + signum == SIGQUIT) + { + if (signum == LL_SMACKDOWN_SIGNAL) + { + // Smackdown treated just like any other app termination, for now + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; + } + else + { + // Don't log anything, even errors - this is because this signal could happen anywhere. + LLError::setDefaultLevel(LLError::LEVEL_NONE); + } + + // Change the signal that we reraise to SIGABRT, so we generate a core dump. + signum = SIGABRT; + } + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; + } + if (LLApp::isError()) + { + // Received second fatal signal while handling first, just die right now + // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. + clear_signals(); + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; + } + raise(signum); + return; + } + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; + } + + if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem + { + clear_signals(); + LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; + raise(signum); + return; + } + + // Flag status to ERROR + LLApp::setError(); + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; + } + clear_signals(); + raise(signum); + return; + } else { + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; + } + } + } } #if LL_LINUX #endif bool unix_post_minidump_callback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded) -{ - // Copy minidump file path into fixed buffer in the app instance to avoid - // heap allocations in a crash handler. - - // path format: /.dmp - auto dirPathLength = strlen(dump_dir); - auto idLength = strlen(minidump_id); - - // The path must not be truncated. - llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); - - char * path = LLApp::instance()->getMiniDumpFilename(); - auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - strncpy(path, dump_dir, remaining); - remaining -= dirPathLength; - path += dirPathLength; - if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') - { - *path++ = '/'; - --remaining; - } - if (remaining > 0) - { - strncpy(path, minidump_id, remaining); - remaining -= idLength; - path += idLength; - strncpy(path, ".dmp", remaining); - } - - LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; - LLApp::runErrorHandler(); - + const char *minidump_id, + void *context, bool succeeded) +{ + // Copy minidump file path into fixed buffer in the app instance to avoid + // heap allocations in a crash handler. + + // path format: /.dmp + auto dirPathLength = strlen(dump_dir); + auto idLength = strlen(minidump_id); + + // The path must not be truncated. + llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); + + char * path = LLApp::instance()->getMiniDumpFilename(); + auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + strncpy(path, dump_dir, remaining); + remaining -= dirPathLength; + path += dirPathLength; + if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + if (remaining > 0) + { + strncpy(path, minidump_id, remaining); + remaining -= idLength; + path += idLength; + strncpy(path, ".dmp", remaining); + } + + LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; + LLApp::runErrorHandler(); + #ifndef LL_RELEASE_FOR_DOWNLOAD - clear_signals(); - return false; + clear_signals(); + return false; #else - return true; + return true; #endif } #endif // !WINDOWS diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index c89f7d12b2..59ff8d3759 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcallbacklist.cpp * @brief A simple list of callback functions to call. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,7 +39,7 @@ *****************************************************************************/ LLCallbackList::LLCallbackList() { - // nothing + // nothing } LLCallbackList::~LLCallbackList() @@ -48,21 +48,21 @@ LLCallbackList::~LLCallbackList() LLCallbackList::handle_t LLCallbackList::addFunction( callback_t func, void *data) { - if (!func) - { - return {}; - } - - // only add one callback per func/data pair - // - if (containsFunction(func, data)) - { - return {}; - } - - auto handle = addFunction([func, data]{ func(data); }); - mLookup.emplace(callback_pair_t(func, data), handle); - return handle; + if (!func) + { + return {}; + } + + // only add one callback per func/data pair + // + if (containsFunction(func, data)) + { + return {}; + } + + auto handle = addFunction([func, data]{ func(data); }); + mLookup.emplace(callback_pair_t(func, data), handle); + return handle; } LLCallbackList::handle_t LLCallbackList::addFunction( const callable_t& func ) @@ -77,17 +77,17 @@ bool LLCallbackList::containsFunction( callback_t func, void *data) bool LLCallbackList::deleteFunction( callback_t func, void *data) { - auto found = mLookup.find(callback_pair_t(func, data)); - if (found != mLookup.end()) - { - mLookup.erase(found); - deleteFunction(found->second); - return true; - } - else - { - return false; - } + auto found = mLookup.find(callback_pair_t(func, data)); + if (found != mLookup.end()) + { + mLookup.erase(found); + deleteFunction(found->second); + return true; + } + else + { + return false; + } } void LLCallbackList::deleteFunction( const handle_t& handle ) @@ -97,8 +97,8 @@ void LLCallbackList::deleteFunction( const handle_t& handle ) void LLCallbackList::deleteAllFunctions() { - mCallbackList = {}; - mLookup.clear(); + mCallbackList = {}; + mLookup.clear(); } void LLCallbackList::callFunctions() diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 2fb27d5ea8..b245b3db94 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -1,25 +1,25 @@ -/** +/** * @file llcallbacklist.h * @brief A simple list of callback functions to call. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,43 +41,43 @@ *****************************************************************************/ class LLCallbackList: public LLSingleton { - LLSINGLETON(LLCallbackList); + LLSINGLETON(LLCallbackList); public: - typedef void (*callback_t)(void*); + typedef void (*callback_t)(void*); - typedef boost::signals2::signal callback_list_t; - typedef callback_list_t::slot_type callable_t; - typedef boost::signals2::connection handle_t; - typedef boost::signals2::scoped_connection temp_handle_t; - typedef std::function bool_func_t; + typedef boost::signals2::signal callback_list_t; + typedef callback_list_t::slot_type callable_t; + typedef boost::signals2::connection handle_t; + typedef boost::signals2::scoped_connection temp_handle_t; + typedef std::function bool_func_t; - ~LLCallbackList(); + ~LLCallbackList(); - handle_t addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) - handle_t addFunction( const callable_t& func ); - bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair - bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found - void deleteFunction( const handle_t& handle ); - void callFunctions(); // calls all functions - void deleteAllFunctions(); + handle_t addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) + handle_t addFunction( const callable_t& func ); + bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair + bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found + void deleteFunction( const handle_t& handle ); + void callFunctions(); // calls all functions + void deleteAllFunctions(); - handle_t doOnIdleOneTime( const callable_t& func ); - handle_t doOnIdleRepeating( const bool_func_t& func ); - bool isRunning(const handle_t& handle) const { return handle.connected(); }; + handle_t doOnIdleOneTime( const callable_t& func ); + handle_t doOnIdleRepeating( const bool_func_t& func ); + bool isRunning(const handle_t& handle) const { return handle.connected(); }; - static void test(); + static void test(); protected: - callback_list_t mCallbackList; - - // "Additional specializations for std::pair and the standard container - // types, as well as utility functions to compose hashes are available in - // boost::hash." - // https://en.cppreference.com/w/cpp/utility/hash - typedef std::pair< callback_t,void* > callback_pair_t; - typedef std::unordered_map> lookup_table; - lookup_table mLookup; + callback_list_t mCallbackList; + + // "Additional specializations for std::pair and the standard container + // types, as well as utility functions to compose hashes are available in + // boost::hash." + // https://en.cppreference.com/w/cpp/utility/hash + typedef std::pair< callback_t,void* > callback_pair_t; + typedef std::unordered_map> lookup_table; + lookup_table mLookup; }; /*-------------------- legacy names in global namespace --------------------*/ diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 6c23444820..592b7cff1b 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldate.cpp * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,36 +44,36 @@ static const LLDate::timestamp DATE_EPOCH = 0.0; static const LLDate::timestamp LL_APR_USEC_PER_SEC = 1000000.0; - // should be APR_USEC_PER_SEC, but that relies on INT64_C which - // isn't defined in glib under our build set up for some reason + // should be APR_USEC_PER_SEC, but that relies on INT64_C which + // isn't defined in glib under our build set up for some reason LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) {} LLDate::LLDate(const LLDate& date) : - mSecondsSinceEpoch(date.mSecondsSinceEpoch) + mSecondsSinceEpoch(date.mSecondsSinceEpoch) {} LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) : - mSecondsSinceEpoch(seconds_since_epoch.value()) + mSecondsSinceEpoch(seconds_since_epoch.value()) {} LLDate::LLDate(const std::string& iso8601_date) { - if(!fromString(iso8601_date)) - { - LL_WARNS() << "date " << iso8601_date << " failed to parse; " - << "ZEROING IT OUT" << LL_ENDL; - mSecondsSinceEpoch = DATE_EPOCH; - } + if(!fromString(iso8601_date)) + { + LL_WARNS() << "date " << iso8601_date << " failed to parse; " + << "ZEROING IT OUT" << LL_ENDL; + mSecondsSinceEpoch = DATE_EPOCH; + } } std::string LLDate::asString() const { - std::ostringstream stream; - toStream(stream); - return stream.str(); + std::ostringstream stream; + toStream(stream); + return stream.str(); } //@ brief Converts time in seconds since EPOCH @@ -83,236 +83,236 @@ std::string LLDate::asString() const // is one of the standards used and the prefered format std::string LLDate::asRFC1123() const { - return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); + return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } std::string LLDate::toHTTPDateString (std::string fmt) const { LL_PROFILE_ZONE_SCOPED; - - time_t locSeconds = (time_t) mSecondsSinceEpoch; - struct tm * gmt = gmtime (&locSeconds); - return toHTTPDateString(gmt, fmt); + + time_t locSeconds = (time_t) mSecondsSinceEpoch; + struct tm * gmt = gmtime (&locSeconds); + return toHTTPDateString(gmt, fmt); } std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { LL_PROFILE_ZONE_SCOPED; - // avoid calling setlocale() unnecessarily - it's expensive. - static std::string prev_locale = ""; - std::string this_locale = LLStringUtil::getLocale(); - if (this_locale != prev_locale) - { - setlocale(LC_TIME, this_locale.c_str()); - prev_locale = this_locale; - } - - // use strftime() as it appears to be faster than std::time_put - char buffer[128]; - strftime(buffer, 128, fmt.c_str(), gmt); - std::string res(buffer); + // avoid calling setlocale() unnecessarily - it's expensive. + static std::string prev_locale = ""; + std::string this_locale = LLStringUtil::getLocale(); + if (this_locale != prev_locale) + { + setlocale(LC_TIME, this_locale.c_str()); + prev_locale = this_locale; + } + + // use strftime() as it appears to be faster than std::time_put + char buffer[128]; + strftime(buffer, 128, fmt.c_str(), gmt); + std::string res(buffer); #if LL_WINDOWS - // Convert from locale-dependant charset to UTF-8 (EXT-8524). - res = ll_convert_string_to_utf8_string(res); + // Convert from locale-dependant charset to UTF-8 (EXT-8524). + res = ll_convert_string_to_utf8_string(res); #endif - return res; + return res; } void LLDate::toStream(std::ostream& s) const { - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); - - apr_time_exp_t exp_time; - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) - { - s << "1970-01-01T00:00:00Z"; - return; - } - - s << std::dec << std::setfill('0'); + apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + + apr_time_exp_t exp_time; + if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) + { + s << "1970-01-01T00:00:00Z"; + return; + } + + s << std::dec << std::setfill('0'); #if( LL_WINDOWS || __GNUC__ > 2) - s << std::right; + s << std::right; #else - s.setf(ios::right); + s.setf(ios::right); #endif - s << std::setw(4) << (exp_time.tm_year + 1900) - << '-' << std::setw(2) << (exp_time.tm_mon + 1) - << '-' << std::setw(2) << (exp_time.tm_mday) - << 'T' << std::setw(2) << (exp_time.tm_hour) - << ':' << std::setw(2) << (exp_time.tm_min) - << ':' << std::setw(2) << (exp_time.tm_sec); - if (exp_time.tm_usec > 0) - { - s << '.' << std::setw(2) - << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); - } - s << 'Z' - << std::setfill(' '); + s << std::setw(4) << (exp_time.tm_year + 1900) + << '-' << std::setw(2) << (exp_time.tm_mon + 1) + << '-' << std::setw(2) << (exp_time.tm_mday) + << 'T' << std::setw(2) << (exp_time.tm_hour) + << ':' << std::setw(2) << (exp_time.tm_min) + << ':' << std::setw(2) << (exp_time.tm_sec); + if (exp_time.tm_usec > 0) + { + s << '.' << std::setw(2) + << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); + } + s << 'Z' + << std::setfill(' '); } bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const { - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); - - apr_time_exp_t exp_time; - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) - { - return false; - } + apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + + apr_time_exp_t exp_time; + if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) + { + return false; + } - if (year) - *year = exp_time.tm_year + 1900; + if (year) + *year = exp_time.tm_year + 1900; - if (month) - *month = exp_time.tm_mon + 1; + if (month) + *month = exp_time.tm_mon + 1; - if (day) - *day = exp_time.tm_mday; + if (day) + *day = exp_time.tm_mday; - if (hour) - *hour = exp_time.tm_hour; + if (hour) + *hour = exp_time.tm_hour; - if (min) - *min = exp_time.tm_min; + if (min) + *min = exp_time.tm_min; - if (sec) - *sec = exp_time.tm_sec; + if (sec) + *sec = exp_time.tm_sec; - return true; + return true; } bool LLDate::fromString(const std::string& iso8601_date) { - std::istringstream stream(iso8601_date); - return fromStream(stream); + std::istringstream stream(iso8601_date); + return fromStream(stream); } bool LLDate::fromStream(std::istream& s) { - struct apr_time_exp_t exp_time; - apr_int32_t tm_part; - int c; - - s >> tm_part; - exp_time.tm_year = tm_part - 1900; - c = s.get(); // skip the hypen - if (c != '-') { return false; } - s >> tm_part; - exp_time.tm_mon = tm_part - 1; - c = s.get(); // skip the hypen - if (c != '-') { return false; } - s >> tm_part; - exp_time.tm_mday = tm_part; - - c = s.get(); // skip the T - if (c != 'T') { return false; } - - s >> tm_part; - exp_time.tm_hour = tm_part; - c = s.get(); // skip the : - if (c != ':') { return false; } - s >> tm_part; - exp_time.tm_min = tm_part; - c = s.get(); // skip the : - if (c != ':') { return false; } - s >> tm_part; - exp_time.tm_sec = tm_part; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - timestamp seconds_since_epoch = time / LL_APR_USEC_PER_SEC; - - // check for fractional - c = s.peek(); - if(c == '.') - { - timestamp fractional = 0.0; - s >> fractional; - seconds_since_epoch += fractional; - } - - c = s.peek(); // check for offset - if (c == '+' || c == '-') - { - S32 offset_sign = (c == '+') ? 1 : -1; - S32 offset_hours = 0; - S32 offset_minutes = 0; - S32 offset_in_seconds = 0; - - s >> offset_hours; - - c = s.get(); // skip the colon a get the minutes if there are any - if (c == ':') - { - s >> offset_minutes; - } - - offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; - seconds_since_epoch -= offset_in_seconds; - } - else if (c != 'Z') { return false; } // skip the Z - - mSecondsSinceEpoch = seconds_since_epoch; - return true; + struct apr_time_exp_t exp_time; + apr_int32_t tm_part; + int c; + + s >> tm_part; + exp_time.tm_year = tm_part - 1900; + c = s.get(); // skip the hypen + if (c != '-') { return false; } + s >> tm_part; + exp_time.tm_mon = tm_part - 1; + c = s.get(); // skip the hypen + if (c != '-') { return false; } + s >> tm_part; + exp_time.tm_mday = tm_part; + + c = s.get(); // skip the T + if (c != 'T') { return false; } + + s >> tm_part; + exp_time.tm_hour = tm_part; + c = s.get(); // skip the : + if (c != ':') { return false; } + s >> tm_part; + exp_time.tm_min = tm_part; + c = s.get(); // skip the : + if (c != ':') { return false; } + s >> tm_part; + exp_time.tm_sec = tm_part; + + // zero out the unused fields + exp_time.tm_usec = 0; + exp_time.tm_wday = 0; + exp_time.tm_yday = 0; + exp_time.tm_isdst = 0; + exp_time.tm_gmtoff = 0; + + // generate a time_t from that + apr_time_t time; + if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) + { + return false; + } + + timestamp seconds_since_epoch = time / LL_APR_USEC_PER_SEC; + + // check for fractional + c = s.peek(); + if(c == '.') + { + timestamp fractional = 0.0; + s >> fractional; + seconds_since_epoch += fractional; + } + + c = s.peek(); // check for offset + if (c == '+' || c == '-') + { + S32 offset_sign = (c == '+') ? 1 : -1; + S32 offset_hours = 0; + S32 offset_minutes = 0; + S32 offset_in_seconds = 0; + + s >> offset_hours; + + c = s.get(); // skip the colon a get the minutes if there are any + if (c == ':') + { + s >> offset_minutes; + } + + offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; + seconds_since_epoch -= offset_in_seconds; + } + else if (c != 'Z') { return false; } // skip the Z + + mSecondsSinceEpoch = seconds_since_epoch; + return true; } bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec) { - struct apr_time_exp_t exp_time; - - exp_time.tm_year = year - 1900; - exp_time.tm_mon = month - 1; - exp_time.tm_mday = day; - exp_time.tm_hour = hour; - exp_time.tm_min = min; - exp_time.tm_sec = sec; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; - - return true; + struct apr_time_exp_t exp_time; + + exp_time.tm_year = year - 1900; + exp_time.tm_mon = month - 1; + exp_time.tm_mday = day; + exp_time.tm_hour = hour; + exp_time.tm_min = min; + exp_time.tm_sec = sec; + + // zero out the unused fields + exp_time.tm_usec = 0; + exp_time.tm_wday = 0; + exp_time.tm_yday = 0; + exp_time.tm_isdst = 0; + exp_time.tm_gmtoff = 0; + + // generate a time_t from that + apr_time_t time; + if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) + { + return false; + } + + mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; + + return true; } LLDate::timestamp LLDate::secondsSinceEpoch() const { - return mSecondsSinceEpoch; + return mSecondsSinceEpoch; } void LLDate::secondsSinceEpoch(timestamp seconds) { - mSecondsSinceEpoch = seconds; + mSecondsSinceEpoch = seconds; } /* static */ LLDate LLDate::now() { - // time() returns seconds, we want fractions of a second, which LLTimer provides --RN - return LLDate(LLTimer::getTotalSeconds()); + // time() returns seconds, we want fractions of a second, which LLTimer provides --RN + return LLDate(LLTimer::getTotalSeconds()); } bool LLDate::operator<(const LLDate& rhs) const @@ -322,13 +322,13 @@ bool LLDate::operator<(const LLDate& rhs) const std::ostream& operator<<(std::ostream& s, const LLDate& date) { - date.toStream(s); - return s; + date.toStream(s); + return s; } std::istream& operator>>(std::istream& s, LLDate& date) { - date.fromStream(s); - return s; + date.fromStream(s); + return s; } diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index c3d0cb97f3..772f45ea7c 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -1,4 +1,4 @@ -/** +/** * @file lldate.h * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ #include "stdtypes.h" #include "llunits.h" -/** +/** * @class LLDate * @brief This class represents a particular point in time in UTC. * @@ -44,112 +44,112 @@ class LL_COMMON_API LLDate { public: - using timestamp = F64; - - /** - * @brief Construct a date equal to epoch. - */ - LLDate(); - - /** - * @brief Construct a date equal to the source date. - */ - LLDate(const LLDate& date); - - /** - * @brief Construct a date from a seconds since epoch value. - * - * @param seconds_since_epoch The number of seconds since UTC epoch. - */ - LLDate(F64SecondsImplicit seconds_since_epoch); - - /** - * @brief Construct a date from a string representation - * - * The date is constructed in the fromString() - * method. See that method for details of supported formats. - * If that method fails to parse the date, the date is set to epoch. - * @param iso8601_date An iso-8601 compatible representation of the date. - */ - LLDate(const std::string& iso8601_date); - - /** - * @brief Return the date as in ISO-8601 string. - * - * @return A string representation of the date. - */ - std::string asString() const; - std::string asRFC1123() const; - void toStream(std::ostream&) const; - bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; - std::string toHTTPDateString (std::string fmt) const; - static std::string toHTTPDateString (tm * gmt, std::string fmt); - /** - * @brief Set the date from an ISO-8601 string. - * - * The parser only supports strings conforming to - * YYYYF-MM-DDTHH:MM:SS.FFZ where Y is year, M is month, D is day, - * H is hour, M is minute, S is second, F is sub-second, and all - * other characters are literal. - * If this method fails to parse the date, the previous date is - * retained. - * @param iso8601_date An iso-8601 compatible representation of the date. - * @return Returns true if the string was successfully parsed. - */ - bool fromString(const std::string& iso8601_date); - bool fromStream(std::istream&); - bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0); - - /** - * @brief Return the date in seconds since epoch. - * - * @return The number of seconds since epoch UTC. - */ - timestamp secondsSinceEpoch() const; - - /** - * @brief Set the date in seconds since epoch. - * - * @param seconds The number of seconds since epoch UTC. - */ - void secondsSinceEpoch(timestamp seconds); - + using timestamp = F64; + + /** + * @brief Construct a date equal to epoch. + */ + LLDate(); + + /** + * @brief Construct a date equal to the source date. + */ + LLDate(const LLDate& date); + + /** + * @brief Construct a date from a seconds since epoch value. + * + * @param seconds_since_epoch The number of seconds since UTC epoch. + */ + LLDate(F64SecondsImplicit seconds_since_epoch); + + /** + * @brief Construct a date from a string representation + * + * The date is constructed in the fromString() + * method. See that method for details of supported formats. + * If that method fails to parse the date, the date is set to epoch. + * @param iso8601_date An iso-8601 compatible representation of the date. + */ + LLDate(const std::string& iso8601_date); + + /** + * @brief Return the date as in ISO-8601 string. + * + * @return A string representation of the date. + */ + std::string asString() const; + std::string asRFC1123() const; + void toStream(std::ostream&) const; + bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; + std::string toHTTPDateString (std::string fmt) const; + static std::string toHTTPDateString (tm * gmt, std::string fmt); + /** + * @brief Set the date from an ISO-8601 string. + * + * The parser only supports strings conforming to + * YYYYF-MM-DDTHH:MM:SS.FFZ where Y is year, M is month, D is day, + * H is hour, M is minute, S is second, F is sub-second, and all + * other characters are literal. + * If this method fails to parse the date, the previous date is + * retained. + * @param iso8601_date An iso-8601 compatible representation of the date. + * @return Returns true if the string was successfully parsed. + */ + bool fromString(const std::string& iso8601_date); + bool fromStream(std::istream&); + bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0); + + /** + * @brief Return the date in seconds since epoch. + * + * @return The number of seconds since epoch UTC. + */ + timestamp secondsSinceEpoch() const; + + /** + * @brief Set the date in seconds since epoch. + * + * @param seconds The number of seconds since epoch UTC. + */ + void secondsSinceEpoch(timestamp seconds); + /** * @brief Create an LLDate object set to the current time. - * - * @return The number of seconds since epoch UTC. - */ + * + * @return The number of seconds since epoch UTC. + */ static LLDate now(); - /** - * @brief Compare dates using operator< so we can order them using STL. - * - * @param rhs -- the right hand side of the comparison operator - */ - bool operator<(const LLDate& rhs) const; - - /** - * @brief Remaining comparison operators in terms of operator< + /** + * @brief Compare dates using operator< so we can order them using STL. + * + * @param rhs -- the right hand side of the comparison operator + */ + bool operator<(const LLDate& rhs) const; + + /** + * @brief Remaining comparison operators in terms of operator< * This conforms to the expectation of STL. - * - * @param rhs -- the right hand side of the comparison operator - */ + * + * @param rhs -- the right hand side of the comparison operator + */ bool operator>(const LLDate& rhs) const { return rhs < *this; } bool operator<=(const LLDate& rhs) const { return !(rhs < *this); } bool operator>=(const LLDate& rhs) const { return !(*this < rhs); } bool operator!=(const LLDate& rhs) const { return (*this < rhs) || (rhs < *this); } bool operator==(const LLDate& rhs) const { return !(*this != rhs); } - /** - * @brief Compare to epoch UTC. - */ + /** + * @brief Compare to epoch UTC. + */ + + bool isNull() const { return mSecondsSinceEpoch == 0.0; } + bool notNull() const { return mSecondsSinceEpoch != 0.0; } - bool isNull() const { return mSecondsSinceEpoch == 0.0; } - bool notNull() const { return mSecondsSinceEpoch != 0.0; } - private: - timestamp mSecondsSinceEpoch; + timestamp mSecondsSinceEpoch; }; // Helper function to stream out a date diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index e225119dfb..d19cdd1f25 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -8,21 +8,21 @@ * $LicenseInfo:firstyear=2008&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$ */ @@ -178,7 +178,7 @@ struct LLDependenciesEmpty * values such as NULL or 0 rather than having to write * LLDependenciesEmpty(). */ - LLDependenciesEmpty(void*) {} + LLDependenciesEmpty(void*) {} }; /** @@ -210,7 +210,7 @@ class LLDependencies: public LLDependenciesBase before(before_) {} NODE node; - dep_set after, before; + dep_set after, before; }; typedef std::map DepNodeMap; typedef typename DepNodeMap::value_type DepNodeMapEntry; @@ -240,7 +240,7 @@ public: * NODE& reference. * * @note - * Actual dependency analysis is deferred to the sort() method, so + * Actual dependency analysis is deferred to the sort() method, so * you can add an arbitrary number of nodes without incurring analysis * overhead for each. The flip side of this is that add()ing nodes that * define a cycle leaves this object in a state in which sort() will @@ -599,7 +599,7 @@ public: return sorted_range(begin, end); } - using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; + using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; /// Override base-class describe() with actual implementation virtual std::ostream& describe(std::ostream& out, bool full=true) const diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index b6285db073..3d00fa46c1 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llerror.cpp * @date December 2006 * @brief error message system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -65,91 +65,91 @@ namespace { #if LL_WINDOWS - void debugger_print(const std::string& s) - { - // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C - // which works just fine under the windows debugger, but can cause users who - // have enabled SEHOP exception chain validation to crash due to interactions - // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 - // - if (IsDebuggerPresent()) - { - // Need UTF16 for Unicode OutputDebugString - // - if (s.size()) - { - OutputDebugString(utf8str_to_utf16str(s).c_str()); - OutputDebugString(TEXT("\n")); - } - } - } + void debugger_print(const std::string& s) + { + // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C + // which works just fine under the windows debugger, but can cause users who + // have enabled SEHOP exception chain validation to crash due to interactions + // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 + // + if (IsDebuggerPresent()) + { + // Need UTF16 for Unicode OutputDebugString + // + if (s.size()) + { + OutputDebugString(utf8str_to_utf16str(s).c_str()); + OutputDebugString(TEXT("\n")); + } + } + } #else - class RecordToSyslog : public LLError::Recorder - { - public: - RecordToSyslog(const std::string& identity) - : mIdentity(identity) - { - openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); - // we need to set the string from a local copy of the string - // since apparanetly openlog expects the const char* to remain - // valid even after it returns (presumably until closelog) - } - - ~RecordToSyslog() - { - closelog(); - } + class RecordToSyslog : public LLError::Recorder + { + public: + RecordToSyslog(const std::string& identity) + : mIdentity(identity) + { + openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); + // we need to set the string from a local copy of the string + // since apparanetly openlog expects the const char* to remain + // valid even after it returns (presumably until closelog) + } + + ~RecordToSyslog() + { + closelog(); + } virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x01; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - int syslogPriority = LOG_CRIT; - switch (level) { - case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; - case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; - case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; - case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; - default: syslogPriority = LOG_CRIT; - } - - syslog(syslogPriority, "%s", message.c_str()); - } - private: - std::string mIdentity; - }; + int syslogPriority = LOG_CRIT; + switch (level) { + case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; + case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; + case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; + case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; + default: syslogPriority = LOG_CRIT; + } + + syslog(syslogPriority, "%s", message.c_str()); + } + private: + std::string mIdentity; + }; #endif - class RecordToFile : public LLError::Recorder - { - public: - RecordToFile(const std::string& filename): - mName(filename) - { - mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); - if (!mFile) - { - LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; - } - else - { - if (!LLError::getAlwaysFlush()) - { - mFile.sync_with_stdio(false); - } - } - } - - ~RecordToFile() - { - mFile.close(); - } + class RecordToFile : public LLError::Recorder + { + public: + RecordToFile(const std::string& filename): + mName(filename) + { + mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); + if (!mFile) + { + LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; + } + else + { + if (!LLError::getAlwaysFlush()) + { + mFile.sync_with_stdio(false); + } + } + } + + ~RecordToFile() + { + mFile.close(); + } virtual bool enabled() override { @@ -159,7 +159,7 @@ namespace { return LLError::getEnabledLogTypesMask() & 0x02; #endif } - + bool okay() const { return mFile.good(); } std::string getFilename() const { return mName; } @@ -178,25 +178,25 @@ namespace { } } - private: - const std::string mName; - llofstream mFile; - }; - - - class RecordToStderr : public LLError::Recorder - { - public: - RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) - { + private: + const std::string mName; + llofstream mFile; + }; + + + class RecordToStderr : public LLError::Recorder + { + public: + RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) + { this->showMultiline(true); - } - + } + virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x04; } - + LL_FORCE_INLINE std::string createBoldANSI() { std::string ansi_code; @@ -231,12 +231,12 @@ namespace { return ansi_code; } - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING // The default colors for error, warn and debug are now a bit more pastel - // and easier to read on the default (black) terminal background but you + // and easier to read on the default (black) terminal background but you // now have the option to set the color of each via an environment variables: // LL_ANSI_ERROR_COLOR_CODE (default is red) // LL_ANSI_WARN_COLOR_CODE (default is blue) @@ -256,75 +256,75 @@ namespace { static std::string s_ansi_warn = createANSI(s_ansi_warn_code); // default is blue static std::string s_ansi_debug = createANSI(s_ansi_debug_code); // default is magenta - if (mUseANSI) - { + if (mUseANSI) + { writeANSI((level == LLError::LEVEL_ERROR) ? s_ansi_error : (level == LLError::LEVEL_WARN) ? s_ansi_warn : s_ansi_debug, message); - } + } else { LL_PROFILE_ZONE_NAMED("fprintf"); fprintf(stderr, "%s\n", message.c_str()); } - } - - private: - bool mUseANSI; + } + + private: + bool mUseANSI; LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) - { + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING static std::string s_ansi_bold = createBoldANSI(); // bold text static std::string s_ansi_reset = createResetANSI(); // reset - // ANSI color code escape sequence, message, and reset in one fprintf call + // ANSI color code escape sequence, message, and reset in one fprintf call // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. - fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); - } - - static bool checkANSI(void) - { - // Check whether it's okay to use ANSI; if stderr is - // a tty then we assume yes. Can be turned off with - // the LL_NO_ANSI_COLOR env var. - return (0 != isatty(2)) && - (NULL == getenv("LL_NO_ANSI_COLOR")); - } - }; - - class RecordToFixedBuffer : public LLError::Recorder - { - public: - RecordToFixedBuffer(LLLineBuffer* buffer) + fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); + } + + static bool checkANSI(void) + { + // Check whether it's okay to use ANSI; if stderr is + // a tty then we assume yes. Can be turned off with + // the LL_NO_ANSI_COLOR env var. + return (0 != isatty(2)) && + (NULL == getenv("LL_NO_ANSI_COLOR")); + } + }; + + class RecordToFixedBuffer : public LLError::Recorder + { + public: + RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { this->showMultiline(true); this->showTags(false); this->showLocation(false); } - + virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x08; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - mBuffer->addLine(message); - } - - private: - LLLineBuffer* mBuffer; - }; + mBuffer->addLine(message); + } + + private: + LLLineBuffer* mBuffer; + }; #if LL_WINDOWS - class RecordToWinDebug: public LLError::Recorder - { - public: - RecordToWinDebug() - { + class RecordToWinDebug: public LLError::Recorder + { + public: + RecordToWinDebug() + { this->showMultiline(true); this->showTags(false); this->showLocation(false); @@ -334,154 +334,154 @@ namespace { { return LLError::getEnabledLogTypesMask() & 0x10; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - debugger_print(message); - } - }; + debugger_print(message); + } + }; #endif } namespace { - std::string className(const std::type_info& type) - { - return LLError::Log::demangle(type.name()); - } + std::string className(const std::type_info& type) + { + return LLError::Log::demangle(type.name()); + } } // anonymous namespace LLError { - std::string Log::demangle(const char* mangled) - { + std::string Log::demangle(const char* mangled) + { #ifdef __GNUC__ - // GCC: type_info::name() returns a mangled class name,st demangle - // passing nullptr, 0 forces allocation of a unique buffer we can free - // fixing MAINT-8724 on OSX 10.14 - int status = -1; - char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); - std::string result(name ? name : mangled); - free(name); - return result; + // GCC: type_info::name() returns a mangled class name,st demangle + // passing nullptr, 0 forces allocation of a unique buffer we can free + // fixing MAINT-8724 on OSX 10.14 + int status = -1; + char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); + std::string result(name ? name : mangled); + free(name); + return result; #elif LL_WINDOWS - // Visual Studio: type_info::name() includes the text "class " at the start - std::string name = mangled; - for (const auto& prefix : std::vector{ "class ", "struct " }) - { - if (0 == name.compare(0, prefix.length(), prefix)) - { - return name.substr(prefix.length()); - } - } - // huh, that's odd, we should see one or the other prefix -- but don't - // try to log unless logging is already initialized - // in Python, " or ".join(vector) -- but in C++, a PITB - LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" - << name << "'" << LL_ENDL; - return name; + // Visual Studio: type_info::name() includes the text "class " at the start + std::string name = mangled; + for (const auto& prefix : std::vector{ "class ", "struct " }) + { + if (0 == name.compare(0, prefix.length(), prefix)) + { + return name.substr(prefix.length()); + } + } + // huh, that's odd, we should see one or the other prefix -- but don't + // try to log unless logging is already initialized + // in Python, " or ".join(vector) -- but in C++, a PITB + LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" + << name << "'" << LL_ENDL; + return name; #else // neither GCC nor Visual Studio - return mangled; + return mangled; #endif - } + } } // LLError namespace { - std::string functionName(const std::string& preprocessor_name) - { + std::string functionName(const std::string& preprocessor_name) + { #if LL_WINDOWS - // DevStudio: the __FUNCTION__ macro string includes - // the type and/or namespace prefixes + // DevStudio: the __FUNCTION__ macro string includes + // the type and/or namespace prefixes - std::string::size_type p = preprocessor_name.rfind(':'); - if (p == std::string::npos) - { - return preprocessor_name; - } - return preprocessor_name.substr(p + 1); + std::string::size_type p = preprocessor_name.rfind(':'); + if (p == std::string::npos) + { + return preprocessor_name; + } + return preprocessor_name.substr(p + 1); #else - return preprocessor_name; + return preprocessor_name; #endif - } - - - class LogControlFile : public LLLiveFile - { - LOG_CLASS(LogControlFile); - - public: - static LogControlFile& fromDirectory(const std::string& user_dir, const std::string& app_dir); - - virtual bool loadFile(); - - private: - LogControlFile(const std::string &filename) - : LLLiveFile(filename) - { } - }; - - LogControlFile& LogControlFile::fromDirectory(const std::string& user_dir, const std::string& app_dir) - { + } + + + class LogControlFile : public LLLiveFile + { + LOG_CLASS(LogControlFile); + + public: + static LogControlFile& fromDirectory(const std::string& user_dir, const std::string& app_dir); + + virtual bool loadFile(); + + private: + LogControlFile(const std::string &filename) + : LLLiveFile(filename) + { } + }; + + LogControlFile& LogControlFile::fromDirectory(const std::string& user_dir, const std::string& app_dir) + { // NB: We have no abstraction in llcommon for the "proper" // delimiter but it turns out that "/" works on all three platforms - - std::string file = user_dir + "/logcontrol-dev.xml"; - - llstat stat_info; - if (LLFile::stat(file, &stat_info)) { - // NB: stat returns non-zero if it can't read the file, for example - // if it doesn't exist. LLFile has no better abstraction for - // testing for file existence. - - file = app_dir + "/logcontrol.xml"; - } - return * new LogControlFile(file); - // NB: This instance is never freed - } - - bool LogControlFile::loadFile() - { - LLSD configuration; - - { - llifstream file(filename().c_str()); - if (!file.is_open()) - { - LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; - return false; - } - - if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; - return false; - } - - if (! configuration || !configuration.isMap()) - { - LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" - " content; not changing configuration" - << LL_ENDL; - return false; - } - } - - LLError::configure(configuration); - LL_INFOS("LogControlFile") << "logging reconfigured from " << filename() << LL_ENDL; - return true; - } - - - typedef std::map LevelMap; - typedef std::vector Recorders; - typedef std::vector CallSiteVector; + + std::string file = user_dir + "/logcontrol-dev.xml"; + + llstat stat_info; + if (LLFile::stat(file, &stat_info)) { + // NB: stat returns non-zero if it can't read the file, for example + // if it doesn't exist. LLFile has no better abstraction for + // testing for file existence. + + file = app_dir + "/logcontrol.xml"; + } + return * new LogControlFile(file); + // NB: This instance is never freed + } + + bool LogControlFile::loadFile() + { + LLSD configuration; + + { + llifstream file(filename().c_str()); + if (!file.is_open()) + { + LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; + return false; + } + + if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; + return false; + } + + if (! configuration || !configuration.isMap()) + { + LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" + " content; not changing configuration" + << LL_ENDL; + return false; + } + } + + LLError::configure(configuration); + LL_INFOS("LogControlFile") << "logging reconfigured from " << filename() << LL_ENDL; + return true; + } + + + typedef std::map LevelMap; + typedef std::vector Recorders; + typedef std::vector CallSiteVector; class SettingsConfig : public LLRefCount { @@ -492,9 +492,9 @@ namespace LLError::ELevel mDefaultLevel; - bool mLogAlwaysFlush; + bool mLogAlwaysFlush; - U32 mEnabledLogTypesMask; + U32 mEnabledLogTypesMask; LevelMap mFunctionLevelMap; LevelMap mClassLevelMap; @@ -539,34 +539,34 @@ namespace mRecorders.clear(); } - class Globals - { + class Globals + { public: static Globals* getInstance(); protected: - Globals(); - public: - std::string mFatalMessage; + Globals(); + public: + std::string mFatalMessage; - void addCallSite(LLError::CallSite&); - void invalidateCallSites(); + void addCallSite(LLError::CallSite&); + void invalidateCallSites(); SettingsConfigPtr getSettingsConfig(); void resetSettingsConfig(); LLError::SettingsStoragePtr saveAndResetSettingsConfig(); void restore(LLError::SettingsStoragePtr pSettingsStorage); - private: - CallSiteVector callSites; + private: + CallSiteVector callSites; SettingsConfigPtr mSettingsConfig; - }; + }; - Globals::Globals() - : - callSites(), + Globals::Globals() + : + callSites(), mSettingsConfig(new SettingsConfig()) - { - } + { + } Globals* Globals::getInstance() @@ -579,20 +579,20 @@ namespace return &inst; } - void Globals::addCallSite(LLError::CallSite& site) - { - callSites.push_back(&site); - } - - void Globals::invalidateCallSites() - { - for (LLError::CallSite* site : callSites) - { + void Globals::addCallSite(LLError::CallSite& site) + { + callSites.push_back(&site); + } + + void Globals::invalidateCallSites() + { + for (LLError::CallSite* site : callSites) + { site->invalidate(); - } - - callSites.clear(); - } + } + + callSites.clear(); + } SettingsConfigPtr Globals::getSettingsConfig() { @@ -622,77 +622,77 @@ namespace namespace LLError { - CallSite::CallSite(ELevel level, - const char* file, - int line, - const std::type_info& class_info, - const char* function, - bool printOnce, - const char** tags, - size_t tag_count) - : mLevel(level), - mFile(file), - mLine(line), - mClassInfo(class_info), - mFunction(function), - mCached(false), - mShouldLog(false), - mPrintOnce(printOnce), - mTags(new const char* [tag_count]), - mTagCount(tag_count) - { - switch (mLevel) - { + CallSite::CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool printOnce, + const char** tags, + size_t tag_count) + : mLevel(level), + mFile(file), + mLine(line), + mClassInfo(class_info), + mFunction(function), + mCached(false), + mShouldLog(false), + mPrintOnce(printOnce), + mTags(new const char* [tag_count]), + mTagCount(tag_count) + { + switch (mLevel) + { case LEVEL_DEBUG: mLevelString = "DEBUG"; break; case LEVEL_INFO: mLevelString = "INFO"; break; case LEVEL_WARN: mLevelString = "WARNING"; break; case LEVEL_ERROR: mLevelString = "ERROR"; break; default: mLevelString = "XXX"; break; - }; + }; - mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine); + mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine); #if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name + // DevStudio: __FUNCTION__ already includes the full class name #else #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) #else - if (mClassInfo != typeid(NoClassInfo)) + if (mClassInfo != typeid(NoClassInfo)) #endif // LL_LINUX - { - mFunctionString = className(mClassInfo) + "::"; - } + { + mFunctionString = className(mClassInfo) + "::"; + } #endif - mFunctionString += std::string(mFunction); + mFunctionString += std::string(mFunction); - for (int i = 0; i < tag_count; i++) - { + for (int i = 0; i < tag_count; i++) + { if (strchr(tags[i], ' ')) { LL_ERRS() << "Space is not allowed in a log tag at " << mLocationString << LL_ENDL; } - mTags[i] = tags[i]; - } + mTags[i] = tags[i]; + } mTagString.append("#"); // always construct a tag sequence; will be just a single # if no tag - for (size_t i = 0; i < mTagCount; i++) - { - mTagString.append(mTags[i]); + for (size_t i = 0; i < mTagCount; i++) + { + mTagString.append(mTags[i]); mTagString.append("#"); - } - } - - CallSite::~CallSite() - { - delete []mTags; - } - - void CallSite::invalidate() - { - mCached = false; - } + } + } + + CallSite::~CallSite() + { + delete []mTags; + } + + void CallSite::invalidate() + { + mCached = false; + } } namespace @@ -729,202 +729,202 @@ namespace #endif } - bool stderrLogWantsTime() - { + bool stderrLogWantsTime() + { #if LL_WINDOWS - return false; + return false; #else - return true; + return true; #endif - } - - - void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) - { - Globals::getInstance()->resetSettingsConfig(); - - LLError::setDefaultLevel(LLError::LEVEL_INFO); - LLError::setAlwaysFlush(true); - LLError::setEnabledLogTypesMask(0xFFFFFFFF); - LLError::setTimeFunction(LLError::utcTime); - - // log_to_stderr is only false in the unit and integration tests to keep builds quieter - if (log_to_stderr && shouldLogToStderr()) - { - LLError::logToStderr(); - } + } + + + void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) + { + Globals::getInstance()->resetSettingsConfig(); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + LLError::setAlwaysFlush(true); + LLError::setEnabledLogTypesMask(0xFFFFFFFF); + LLError::setTimeFunction(LLError::utcTime); + + // log_to_stderr is only false in the unit and integration tests to keep builds quieter + if (log_to_stderr && shouldLogToStderr()) + { + LLError::logToStderr(); + } #if LL_WINDOWS - LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); - LLError::addRecorder(recordToWinDebug); + LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); + LLError::addRecorder(recordToWinDebug); #endif - LogControlFile& e = LogControlFile::fromDirectory(user_dir, app_dir); - - // NOTE: We want to explicitly load the file before we add it to the event timer - // that checks for changes to the file. Else, we're not actually loading the file yet, - // and most of the initialization happens without any attention being paid to the - // log control file. Not to mention that when it finally gets checked later, - // all log statements that have been evaluated already become dirty and need to be - // evaluated for printing again. So, make sure to call checkAndReload() - // before addToEventTimer(). - e.checkAndReload(); - e.addToEventTimer(); - } + LogControlFile& e = LogControlFile::fromDirectory(user_dir, app_dir); + + // NOTE: We want to explicitly load the file before we add it to the event timer + // that checks for changes to the file. Else, we're not actually loading the file yet, + // and most of the initialization happens without any attention being paid to the + // log control file. Not to mention that when it finally gets checked later, + // all log statements that have been evaluated already become dirty and need to be + // evaluated for printing again. So, make sure to call checkAndReload() + // before addToEventTimer(). + e.checkAndReload(); + e.addToEventTimer(); + } } namespace LLError { - void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr) - { - commonInit(user_dir, app_dir, log_to_stderr); - } - - void setFatalFunction(const FatalFunction& f) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mCrashFunction = f; - } - - FatalFunction getFatalFunction() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mCrashFunction; - } - - std::string getFatalMessage() - { - return Globals::getInstance()->mFatalMessage; - } - - void setTimeFunction(TimeFunction f) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mTimeFunction = f; - } - - void setDefaultLevel(ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mDefaultLevel = level; - } - - ELevel getDefaultLevel() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mDefaultLevel; - } - - void setAlwaysFlush(bool flush) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mLogAlwaysFlush = flush; - } - - bool getAlwaysFlush() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mLogAlwaysFlush; - } - - void setEnabledLogTypesMask(U32 mask) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mEnabledLogTypesMask = mask; - } - - U32 getEnabledLogTypesMask() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mEnabledLogTypesMask; - } - - void setFunctionLevel(const std::string& function_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mFunctionLevelMap[function_name] = level; - } - - void setClassLevel(const std::string& class_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mClassLevelMap[class_name] = level; - } - - void setFileLevel(const std::string& file_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mFileLevelMap[file_name] = level; - } - - void setTagLevel(const std::string& tag_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mTagLevelMap[tag_name] = level; - } - - LLError::ELevel decodeLevel(std::string name) - { - static LevelMap level_names; - if (level_names.empty()) - { - level_names["ALL"] = LLError::LEVEL_ALL; - level_names["DEBUG"] = LLError::LEVEL_DEBUG; - level_names["INFO"] = LLError::LEVEL_INFO; - level_names["WARN"] = LLError::LEVEL_WARN; - level_names["ERROR"] = LLError::LEVEL_ERROR; - level_names["NONE"] = LLError::LEVEL_NONE; - } - - std::transform(name.begin(), name.end(), name.begin(), toupper); - - LevelMap::const_iterator i = level_names.find(name); - if (i == level_names.end()) - { - LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; - return LLError::LEVEL_INFO; - } - - return i->second; - } + void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr) + { + commonInit(user_dir, app_dir, log_to_stderr); + } + + void setFatalFunction(const FatalFunction& f) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mCrashFunction = f; + } + + FatalFunction getFatalFunction() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mCrashFunction; + } + + std::string getFatalMessage() + { + return Globals::getInstance()->mFatalMessage; + } + + void setTimeFunction(TimeFunction f) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mTimeFunction = f; + } + + void setDefaultLevel(ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mDefaultLevel = level; + } + + ELevel getDefaultLevel() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mDefaultLevel; + } + + void setAlwaysFlush(bool flush) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mLogAlwaysFlush = flush; + } + + bool getAlwaysFlush() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mLogAlwaysFlush; + } + + void setEnabledLogTypesMask(U32 mask) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mEnabledLogTypesMask = mask; + } + + U32 getEnabledLogTypesMask() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mEnabledLogTypesMask; + } + + void setFunctionLevel(const std::string& function_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mFunctionLevelMap[function_name] = level; + } + + void setClassLevel(const std::string& class_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mClassLevelMap[class_name] = level; + } + + void setFileLevel(const std::string& file_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mFileLevelMap[file_name] = level; + } + + void setTagLevel(const std::string& tag_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mTagLevelMap[tag_name] = level; + } + + LLError::ELevel decodeLevel(std::string name) + { + static LevelMap level_names; + if (level_names.empty()) + { + level_names["ALL"] = LLError::LEVEL_ALL; + level_names["DEBUG"] = LLError::LEVEL_DEBUG; + level_names["INFO"] = LLError::LEVEL_INFO; + level_names["WARN"] = LLError::LEVEL_WARN; + level_names["ERROR"] = LLError::LEVEL_ERROR; + level_names["NONE"] = LLError::LEVEL_NONE; + } + + std::transform(name.begin(), name.end(), name.begin(), toupper); + + LevelMap::const_iterator i = level_names.find(name); + if (i == level_names.end()) + { + LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; + return LLError::LEVEL_INFO; + } + + return i->second; + } } namespace { - void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) - { - LLSD::array_const_iterator i, end; - for (i = list.beginArray(), end = list.endArray(); i != end; ++i) - { - map[*i] = level; - } - } + void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) + { + LLSD::array_const_iterator i, end; + for (i = list.beginArray(), end = list.endArray(); i != end; ++i) + { + map[*i] = level; + } + } } namespace LLError { - void configure(const LLSD& config) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - - s->mFunctionLevelMap.clear(); - s->mClassLevelMap.clear(); - s->mFileLevelMap.clear(); - s->mTagLevelMap.clear(); - s->mUniqueLogMessages.clear(); - - setDefaultLevel(decodeLevel(config["default-level"])); + void configure(const LLSD& config) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + + s->mFunctionLevelMap.clear(); + s->mClassLevelMap.clear(); + s->mFileLevelMap.clear(); + s->mTagLevelMap.clear(); + s->mUniqueLogMessages.clear(); + + setDefaultLevel(decodeLevel(config["default-level"])); if (config.has("log-always-flush")) { setAlwaysFlush(config["log-always-flush"]); @@ -933,7 +933,7 @@ namespace LLError { setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger()); } - + if (config.has("settings") && config["settings"].isArray()) { LLSD sets = config["settings"]; @@ -952,66 +952,66 @@ namespace LLError } } } - } + } } namespace LLError { - Recorder::Recorder() - : mWantsTime(true) + Recorder::Recorder() + : mWantsTime(true) , mWantsTags(true) , mWantsLevel(true) , mWantsLocation(true) , mWantsFunctionName(true) , mWantsMultiline(false) - { - } - - Recorder::~Recorder() - { - } - - bool Recorder::wantsTime() - { - return mWantsTime; - } - - // virtual - bool Recorder::wantsTags() - { - return mWantsTags; - } - - // virtual - bool Recorder::wantsLevel() - { - return mWantsLevel; - } - - // virtual - bool Recorder::wantsLocation() - { - return mWantsLocation; - } - - // virtual - bool Recorder::wantsFunctionName() - { - return mWantsFunctionName; - } - - // virtual - bool Recorder::wantsMultiline() - { - return mWantsMultiline; - } + { + } + + Recorder::~Recorder() + { + } + + bool Recorder::wantsTime() + { + return mWantsTime; + } + + // virtual + bool Recorder::wantsTags() + { + return mWantsTags; + } + + // virtual + bool Recorder::wantsLevel() + { + return mWantsLevel; + } + + // virtual + bool Recorder::wantsLocation() + { + return mWantsLocation; + } + + // virtual + bool Recorder::wantsFunctionName() + { + return mWantsFunctionName; + } + + // virtual + bool Recorder::wantsMultiline() + { + return mWantsMultiline; + } void Recorder::showTime(bool show) { mWantsTime = show; } - + void Recorder::showTags(bool show) { mWantsTags = show; @@ -1037,28 +1037,28 @@ namespace LLError mWantsMultiline = show; } - void addRecorder(RecorderPtr recorder) - { - if (!recorder) - { - return; - } - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); - s->mRecorders.push_back(recorder); - } - - void removeRecorder(RecorderPtr recorder) - { - if (!recorder) - { - return; - } - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); - s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), - s->mRecorders.end()); - } + void addRecorder(RecorderPtr recorder) + { + if (!recorder) + { + return; + } + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + s->mRecorders.push_back(recorder); + } + + void removeRecorder(RecorderPtr recorder) + { + if (!recorder) + { + return; + } + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), + s->mRecorders.end()); + } // Find an entry in SettingsConfig::mRecorders whose RecorderPtr points to // a Recorder subclass of type RECORDER. Return, not a RecorderPtr (which @@ -1127,26 +1127,26 @@ namespace LLError namespace LLError { - void logToFile(const std::string& file_name) - { - // remove any previous Recorder filling this role - removeRecorder(); - - if (!file_name.empty()) - { - std::shared_ptr recordToFile(new RecordToFile(file_name)); - if (recordToFile->okay()) - { - addRecorder(recordToFile); - } - } - } - - std::string logFileName() - { - auto found = findRecorder(); - return found? found->getFilename() : std::string(); - } + void logToFile(const std::string& file_name) + { + // remove any previous Recorder filling this role + removeRecorder(); + + if (!file_name.empty()) + { + std::shared_ptr recordToFile(new RecordToFile(file_name)); + if (recordToFile->okay()) + { + addRecorder(recordToFile); + } + } + } + + std::string logFileName() + { + auto found = findRecorder(); + return found? found->getFilename() : std::string(); + } void logToStderr() { @@ -1157,17 +1157,17 @@ namespace LLError } } - void logToFixedBuffer(LLLineBuffer* fixedBuffer) - { - // remove any previous Recorder filling this role - removeRecorder(); + void logToFixedBuffer(LLLineBuffer* fixedBuffer) + { + // remove any previous Recorder filling this role + removeRecorder(); - if (fixedBuffer) - { - RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); - addRecorder(recordToFixedBuffer); - } - } + if (fixedBuffer) + { + RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); + addRecorder(recordToFixedBuffer); + } + } } namespace @@ -1213,40 +1213,40 @@ namespace return out.str(); } - void writeToRecorders(const LLError::CallSite& site, const std::string& message) - { + void writeToRecorders(const LLError::CallSite& site, const std::string& message) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLError::ELevel level = site.mLevel; - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLError::ELevel level = site.mLevel; + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); std::string escaped_message; LLMutexLock lock(&s->mRecorderMutex); - for (LLError::RecorderPtr& r : s->mRecorders) - { + for (LLError::RecorderPtr& r : s->mRecorders) + { if (!r->enabled()) { continue; } - - std::ostringstream message_stream; - if (r->wantsTime() && s->mTimeFunction != NULL) - { - message_stream << s->mTimeFunction(); - } + std::ostringstream message_stream; + + if (r->wantsTime() && s->mTimeFunction != NULL) + { + message_stream << s->mTimeFunction(); + } message_stream << " "; - - if (r->wantsLevel()) + + if (r->wantsLevel()) { - message_stream << site.mLevelString; + message_stream << site.mLevelString; } message_stream << " "; - - if (r->wantsTags()) - { - message_stream << site.mTagString; - } + + if (r->wantsTags()) + { + message_stream << site.mTagString; + } message_stream << " "; if (r->wantsLocation() || level == LLError::LEVEL_ERROR) @@ -1255,10 +1255,10 @@ namespace } message_stream << " "; - if (r->wantsFunctionName()) - { - message_stream << site.mFunctionString; - } + if (r->wantsFunctionName()) + { + message_stream << site.mFunctionString; + } message_stream << " : "; if (r->wantsMultiline()) @@ -1274,251 +1274,251 @@ namespace message_stream << escaped_message; } - r->recordMessage(level, message_stream.str()); - } - } + r->recordMessage(level, message_stream.str()); + } + } } namespace { - // We need a couple different mutexes, but we want to use the same mechanism - // for both. Make getMutex() a template function with different instances - // for different MutexDiscriminator values. - enum MutexDiscriminator - { - LOG_MUTEX, - STACKS_MUTEX - }; - // Some logging calls happen very early in processing -- so early that our - // module-static variables aren't yet initialized. getMutex() wraps a - // function-static LLMutex so that early calls can still have a valid - // LLMutex instance. - template - LLMutex* getMutex() - { - // guaranteed to be initialized the first time control reaches here - static LLMutex sMutex; - return &sMutex; - } - - bool checkLevelMap(const LevelMap& map, const std::string& key, - LLError::ELevel& level) - { - bool stop_checking; - LevelMap::const_iterator i = map.find(key); - if (i == map.end()) - { - return stop_checking = false; - } - - level = i->second; - return stop_checking = true; - } - - bool checkLevelMap( const LevelMap& map, - const char *const * keys, - size_t count, - LLError::ELevel& level) - { - bool found_level = false; - - LLError::ELevel tag_level = LLError::LEVEL_NONE; - - for (size_t i = 0; i < count; i++) - { - LevelMap::const_iterator it = map.find(keys[i]); - if (it != map.end()) - { - found_level = true; - tag_level = llmin(tag_level, it->second); - } - } - - if (found_level) - { - level = tag_level; - } - return found_level; - } + // We need a couple different mutexes, but we want to use the same mechanism + // for both. Make getMutex() a template function with different instances + // for different MutexDiscriminator values. + enum MutexDiscriminator + { + LOG_MUTEX, + STACKS_MUTEX + }; + // Some logging calls happen very early in processing -- so early that our + // module-static variables aren't yet initialized. getMutex() wraps a + // function-static LLMutex so that early calls can still have a valid + // LLMutex instance. + template + LLMutex* getMutex() + { + // guaranteed to be initialized the first time control reaches here + static LLMutex sMutex; + return &sMutex; + } + + bool checkLevelMap(const LevelMap& map, const std::string& key, + LLError::ELevel& level) + { + bool stop_checking; + LevelMap::const_iterator i = map.find(key); + if (i == map.end()) + { + return stop_checking = false; + } + + level = i->second; + return stop_checking = true; + } + + bool checkLevelMap( const LevelMap& map, + const char *const * keys, + size_t count, + LLError::ELevel& level) + { + bool found_level = false; + + LLError::ELevel tag_level = LLError::LEVEL_NONE; + + for (size_t i = 0; i < count; i++) + { + LevelMap::const_iterator it = map.find(keys[i]); + if (it != map.end()) + { + found_level = true; + tag_level = llmin(tag_level, it->second); + } + } + + if (found_level) + { + level = tag_level; + } + return found_level; + } } namespace LLError { - bool Log::shouldLog(CallSite& site) - { + bool Log::shouldLog(CallSite& site) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLMutexTrylock lock(getMutex(), 5); - if (!lock.isLocked()) - { - return false; - } - - Globals *g = Globals::getInstance(); - SettingsConfigPtr s = g->getSettingsConfig(); - - s->mShouldLogCallCounter++; - - const std::string& class_name = className(site.mClassInfo); - std::string function_name = functionName(site.mFunction); + LLMutexTrylock lock(getMutex(), 5); + if (!lock.isLocked()) + { + return false; + } + + Globals *g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); + + s->mShouldLogCallCounter++; + + const std::string& class_name = className(site.mClassInfo); + std::string function_name = functionName(site.mFunction); #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) #else - if (site.mClassInfo != typeid(NoClassInfo)) + if (site.mClassInfo != typeid(NoClassInfo)) #endif // LL_LINUX - { - function_name = class_name + "::" + function_name; - } - - ELevel compareLevel = s->mDefaultLevel; - - // The most specific match found will be used as the log level, - // since the computation short circuits. - // So, in increasing order of importance: - // Default < Tags < File < Class < Function - checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) - || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) - || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) - || (site.mTagCount > 0 - ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) - : false); - - site.mCached = true; - g->addCallSite(site); - return site.mShouldLog = site.mLevel >= compareLevel; - } - - - void Log::flush(const std::ostringstream& out, const CallSite& site) - { + { + function_name = class_name + "::" + function_name; + } + + ELevel compareLevel = s->mDefaultLevel; + + // The most specific match found will be used as the log level, + // since the computation short circuits. + // So, in increasing order of importance: + // Default < Tags < File < Class < Function + checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) + || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) + || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) + || (site.mTagCount > 0 + ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) + : false); + + site.mCached = true; + g->addCallSite(site); + return site.mShouldLog = site.mLevel >= compareLevel; + } + + + void Log::flush(const std::ostringstream& out, const CallSite& site) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLMutexTrylock lock(getMutex(),5); - if (!lock.isLocked()) - { - return; - } - - Globals* g = Globals::getInstance(); - SettingsConfigPtr s = g->getSettingsConfig(); - - std::string message = out.str(); - - if (site.mPrintOnce) - { - std::ostringstream message_stream; - - std::map::iterator messageIter = s->mUniqueLogMessages.find(message); - if (messageIter != s->mUniqueLogMessages.end()) - { - messageIter->second++; - unsigned int num_messages = messageIter->second; - if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) - { - message_stream << "ONCE (" << num_messages << "th time seen): "; - } - else - { - return; - } - } - else - { - message_stream << "ONCE: "; - s->mUniqueLogMessages[message] = 1; - } - message_stream << message; - message = message_stream.str(); - } - - writeToRecorders(site, message); - - if (site.mLevel == LEVEL_ERROR) - { - writeToRecorders(site, stringize(boost::stacktrace::stacktrace())); - g->mFatalMessage = message; - if (s->mCrashFunction) - { - s->mCrashFunction(message); - } - } - } + LLMutexTrylock lock(getMutex(),5); + if (!lock.isLocked()) + { + return; + } + + Globals* g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); + + std::string message = out.str(); + + if (site.mPrintOnce) + { + std::ostringstream message_stream; + + std::map::iterator messageIter = s->mUniqueLogMessages.find(message); + if (messageIter != s->mUniqueLogMessages.end()) + { + messageIter->second++; + unsigned int num_messages = messageIter->second; + if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) + { + message_stream << "ONCE (" << num_messages << "th time seen): "; + } + else + { + return; + } + } + else + { + message_stream << "ONCE: "; + s->mUniqueLogMessages[message] = 1; + } + message_stream << message; + message = message_stream.str(); + } + + writeToRecorders(site, message); + + if (site.mLevel == LEVEL_ERROR) + { + writeToRecorders(site, stringize(boost::stacktrace::stacktrace())); + g->mFatalMessage = message; + if (s->mCrashFunction) + { + s->mCrashFunction(message); + } + } + } } namespace LLError { - SettingsStoragePtr saveAndResetSettings() - { - return Globals::getInstance()->saveAndResetSettingsConfig(); - } - - void restoreSettings(SettingsStoragePtr pSettingsStorage) - { - return Globals::getInstance()->restore(pSettingsStorage); - } - - std::string removePrefix(std::string& s, const std::string& p) - { - std::string::size_type where = s.find(p); - if (where == std::string::npos) - { - return s; - } - - return std::string(s, where + p.size()); - } - - void replaceChar(std::string& s, char old, char replacement) - { - std::string::size_type i = 0; - std::string::size_type len = s.length(); - for ( ; i < len; i++ ) - { - if (s[i] == old) - { - s[i] = replacement; - } - } - } - - std::string abbreviateFile(const std::string& filePath) - { - std::string f = filePath; + SettingsStoragePtr saveAndResetSettings() + { + return Globals::getInstance()->saveAndResetSettingsConfig(); + } + + void restoreSettings(SettingsStoragePtr pSettingsStorage) + { + return Globals::getInstance()->restore(pSettingsStorage); + } + + std::string removePrefix(std::string& s, const std::string& p) + { + std::string::size_type where = s.find(p); + if (where == std::string::npos) + { + return s; + } + + return std::string(s, where + p.size()); + } + + void replaceChar(std::string& s, char old, char replacement) + { + std::string::size_type i = 0; + std::string::size_type len = s.length(); + for ( ; i < len; i++ ) + { + if (s[i] == old) + { + s[i] = replacement; + } + } + } + + std::string abbreviateFile(const std::string& filePath) + { + std::string f = filePath; #if LL_WINDOWS - replaceChar(f, '\\', '/'); + replaceChar(f, '\\', '/'); #endif - static std::string indra_prefix = "indra/"; - f = removePrefix(f, indra_prefix); + static std::string indra_prefix = "indra/"; + f = removePrefix(f, indra_prefix); #if LL_DARWIN - static std::string newview_prefix = "newview/../"; - f = removePrefix(f, newview_prefix); + static std::string newview_prefix = "newview/../"; + f = removePrefix(f, newview_prefix); #endif - return f; - } - - int shouldLogCallCount() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mShouldLogCallCounter; - } - - std::string utcTime() - { - time_t now = time(NULL); - const size_t BUF_SIZE = 64; - char time_str[BUF_SIZE]; /* Flawfinder: ignore */ - - auto chars = strftime(time_str, BUF_SIZE, - "%Y-%m-%dT%H:%M:%SZ", - gmtime(&now)); - - return chars ? time_str : "time error"; - } + return f; + } + + int shouldLogCallCount() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mShouldLogCallCounter; + } + + std::string utcTime() + { + time_t now = time(NULL); + const size_t BUF_SIZE = 64; + char time_str[BUF_SIZE]; /* Flawfinder: ignore */ + + auto chars = strftime(time_str, BUF_SIZE, + "%Y-%m-%dT%H:%M:%SZ", + gmtime(&now)); + + return chars ? time_str : "time error"; + } } namespace LLError -{ +{ LLCallStacks::StringVector LLCallStacks::sBuffer ; //static @@ -1577,7 +1577,7 @@ namespace LLError LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend()); ri != re; ++ri) - { + { LL_INFOS() << (*ri) << LL_ENDL; } LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 2cc1f91408..d0686bd8b5 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -6,25 +6,25 @@ * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System, * originally introduced in llnotifications.h. It has nothing * whatsoever to do with the older system in llevent.h. - * + * * $LicenseInfo:firstyear=2008&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$ */ @@ -39,13 +39,13 @@ #include #include #if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) #endif #include #if LL_WINDOWS - #pragma warning (pop) + #pragma warning (pop) #endif #include @@ -290,9 +290,9 @@ public: /** * Find the named LLEventPump instance. If it exists post the message to it. * If the pump does not exist, do nothing. - * + * * returns the result of the LLEventPump::post. If no pump exists returns false. - * + * * This is syntactically similar to LLEventPumps::instance().post(name, message), * however if the pump does not already exist it will not be created. */ @@ -521,10 +521,10 @@ public: * instantiate your listener, then passing the same name on each listen() * call, allows us to optimize away the second and subsequent dependency * sorts. - * - * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire - * dependency and ordering calculation. In this case, it is critical that - * the result be assigned to a LLTempBoundListener or the listener is + * + * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire + * dependency and ordering calculation. In this case, it is critical that + * the result be assigned to a LLTempBoundListener or the listener is * manually disconnected when no longer needed since there will be no * way to later find and disconnect this listener manually. */ @@ -582,7 +582,7 @@ protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, const NameList& after, const NameList& before); - + /// implement the dispatching std::shared_ptr mSignal; @@ -635,21 +635,21 @@ public: * by all listeners, until some listener consumes it. The caveat is that each * event *must* eventually reach a listener that will consume it, else the * queue will grow to arbitrary length. - * + * * @NOTE: When using an LLEventMailDrop with an LLEventTimeout or * LLEventFilter attaching the filter downstream, using Timeout's constructor will - * cause the MailDrop to discharge any of its stored events. The timeout should - * instead be connected upstream using its listen() method. + * cause the MailDrop to discharge any of its stored events. The timeout should + * instead be connected upstream using its listen() method. */ class LL_COMMON_API LLEventMailDrop : public LLEventStream { public: LLEventMailDrop(const std::string& name, bool tweak = false) : LLEventStream(name, tweak) {} virtual ~LLEventMailDrop() {} - + /// Post an event to all listeners virtual bool post(const LLSD& event) override; - + /// Remove any history stored in the mail drop. void discard(); diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index 43c1a255ac..cc227193cd 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lleventtimer.cpp - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&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$ */ @@ -29,7 +29,7 @@ ////////////////////////////////////////////////////////////////////////////// // -// LLEventTimer Implementation +// LLEventTimer Implementation // ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index a325c704e0..b37d682d29 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -1,25 +1,25 @@ -/** +/** * @file lleventtimer.h - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&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$ */ @@ -36,22 +36,22 @@ class LL_COMMON_API LLEventTimer { public: - LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds - LLEventTimer(const LLDate& time); - virtual ~LLEventTimer(); + LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds + LLEventTimer(const LLDate& time); + virtual ~LLEventTimer(); - void start(); - void stop(); - bool isRunning(); - F32 getRemaining(); + void start(); + void stop(); + bool isRunning(); + F32 getRemaining(); - //function to be called at the supplied frequency - // Normally return false; true will delete the timer after the function returns. - virtual bool tick() = 0; + //function to be called at the supplied frequency + // Normally return false; true will delete the timer after the function returns. + virtual bool tick() = 0; protected: - LL::Timers::temp_handle_t mTimer; - F32 mPeriod; + LL::Timers::temp_handle_t mTimer; + F32 mPeriod; }; #endif //LL_EVENTTIMER_H diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp index 692a21c1f1..774d70eb31 100644 --- a/indra/llcommon/lllivefile.cpp +++ b/indra/llcommon/lllivefile.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lllivefile.cpp * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,51 +35,51 @@ const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f; class LLLiveFile::Impl { public: - Impl(const std::string& filename, const F32 refresh_period); - ~Impl(); - - bool check(); - void changed(); - - bool mForceCheck; - F32 mRefreshPeriod; - LLFrameTimer mRefreshTimer; - - std::string mFilename; - time_t mLastModTime; - time_t mLastStatTime; - bool mLastExists; - - LLEventTimer* mEventTimer; + Impl(const std::string& filename, const F32 refresh_period); + ~Impl(); + + bool check(); + void changed(); + + bool mForceCheck; + F32 mRefreshPeriod; + LLFrameTimer mRefreshTimer; + + std::string mFilename; + time_t mLastModTime; + time_t mLastStatTime; + bool mLastExists; + + LLEventTimer* mEventTimer; private: LOG_CLASS(LLLiveFile); }; LLLiveFile::Impl::Impl(const std::string& filename, const F32 refresh_period) - : - mForceCheck(true), - mRefreshPeriod(refresh_period), - mFilename(filename), - mLastModTime(0), - mLastStatTime(0), - mLastExists(false), - mEventTimer(NULL) + : + mForceCheck(true), + mRefreshPeriod(refresh_period), + mFilename(filename), + mLastModTime(0), + mLastStatTime(0), + mLastExists(false), + mEventTimer(NULL) { } LLLiveFile::Impl::~Impl() { - delete mEventTimer; + delete mEventTimer; } LLLiveFile::LLLiveFile(const std::string& filename, const F32 refresh_period) - : impl(* new Impl(filename, refresh_period)) + : impl(* new Impl(filename, refresh_period)) { } LLLiveFile::~LLLiveFile() { - delete &impl; + delete &impl; } @@ -88,8 +88,8 @@ bool LLLiveFile::Impl::check() bool detected_change = false; // Skip the check if not enough time has elapsed and we're not // forcing a check of the file - if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) - { + if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) + { mForceCheck = false; // force only forces one check mRefreshTimer.reset(); // don't check again until mRefreshPeriod has passed @@ -98,11 +98,11 @@ bool LLLiveFile::Impl::check() if (LLFile::stat(mFilename, &stat_data)) { // Couldn't stat the file, that means it doesn't exist or is - // broken somehow. + // broken somehow. if (mLastExists) { mLastExists = false; - detected_change = true; // no longer existing is a change! + detected_change = true; // no longer existing is a change! LL_DEBUGS() << "detected deleted file '" << mFilename << "'" << LL_ENDL; } } @@ -134,65 +134,65 @@ bool LLLiveFile::Impl::check() void LLLiveFile::Impl::changed() { - // we wanted to read this file, and we were successful. - mLastModTime = mLastStatTime; + // we wanted to read this file, and we were successful. + mLastModTime = mLastStatTime; } bool LLLiveFile::checkAndReload() { - bool changed = impl.check(); - if (changed) - { - if(loadFile()) - { - impl.changed(); - this->changed(); - } - else - { - changed = false; - } - } - return changed; + bool changed = impl.check(); + if (changed) + { + if(loadFile()) + { + impl.changed(); + this->changed(); + } + else + { + changed = false; + } + } + return changed; } std::string LLLiveFile::filename() const { - return impl.mFilename; + return impl.mFilename; } namespace { - class LiveFileEventTimer : public LLEventTimer - { - public: - LiveFileEventTimer(LLLiveFile& f, F32 refresh) - : LLEventTimer(refresh), mLiveFile(f) - { } - - bool tick() override - { - mLiveFile.checkAndReload(); - return FALSE; - } - - private: - LLLiveFile& mLiveFile; - }; - + class LiveFileEventTimer : public LLEventTimer + { + public: + LiveFileEventTimer(LLLiveFile& f, F32 refresh) + : LLEventTimer(refresh), mLiveFile(f) + { } + + bool tick() override + { + mLiveFile.checkAndReload(); + return FALSE; + } + + private: + LLLiveFile& mLiveFile; + }; + } void LLLiveFile::addToEventTimer() { - impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); + impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); } void LLLiveFile::setRefreshPeriod(F32 seconds) { - if (seconds < 0.f) - { - seconds = -seconds; - } - impl.mRefreshPeriod = seconds; + if (seconds < 0.f) + { + seconds = -seconds; + } + impl.mRefreshPeriod = seconds; } diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 5789b5de2c..7ac080b5d6 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -1,25 +1,25 @@ -/** +/** * @file llrefcount.h * @brief Base class for reference counted objects for use with LLPointer * * $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$ */ @@ -45,42 +45,42 @@ extern const S32 gMaxRefCount; class LL_COMMON_API LLRefCount { protected: - LLRefCount(const LLRefCount& other); - LLRefCount& operator=(const LLRefCount&); - virtual ~LLRefCount(); // use unref() - + LLRefCount(const LLRefCount& other); + LLRefCount& operator=(const LLRefCount&); + virtual ~LLRefCount(); // use unref() + public: - LLRefCount(); - - inline void ref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - mRef++; - llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak - } - - inline S32 unref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - llassert(mRef > 0); // ref count below 1, likely corrupted - if (0 == --mRef) - { - mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging - delete this; - return 0; - } - return mRef; - } - - //NOTE: when passing around a const LLRefCount object, this can return different results - // at different types, since mRef is mutable - S32 getNumRefs() const - { - return mRef; - } + LLRefCount(); + + inline void ref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + mRef++; + llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak + } + + inline S32 unref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + llassert(mRef > 0); // ref count below 1, likely corrupted + if (0 == --mRef) + { + mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging + delete this; + return 0; + } + return mRef; + } + + //NOTE: when passing around a const LLRefCount object, this can return different results + // at different types, since mRef is mutable + S32 getNumRefs() const + { + return mRef; + } private: - mutable S32 mRef; + mutable S32 mRef; }; @@ -91,50 +91,50 @@ private: class LL_COMMON_API LLThreadSafeRefCount { public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex + static void initThreadSafeRefCount(); // creates sMutex + static void cleanupThreadSafeRefCount(); // destroys sMutex private: - static LLMutex* sMutex; + static LLMutex* sMutex; protected: - virtual ~LLThreadSafeRefCount(); // use unref() + virtual ~LLThreadSafeRefCount(); // use unref() public: - LLThreadSafeRefCount(); - LLThreadSafeRefCount(const LLThreadSafeRefCount&); - LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) - { - mRef = 0; - return *this; - } - - void ref() - { - mRef++; - } - - void unref() - { - llassert(mRef >= 1); - if ((--mRef) == 0) - { - // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. - // It is technically possible for a vanilla pointer to mess this up, or another thread to - // jump in, find this object, create another smart pointer and end up dangling, but if - // the code is that bad and not thread-safe, it's trouble already. - delete this; - } - } - - S32 getNumRefs() const - { - const S32 currentVal = mRef.CurrentValue(); - return currentVal; - } + LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + { + mRef = 0; + return *this; + } + + void ref() + { + mRef++; + } + + void unref() + { + llassert(mRef >= 1); + if ((--mRef) == 0) + { + // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. + // It is technically possible for a vanilla pointer to mess this up, or another thread to + // jump in, find this object, create another smart pointer and end up dangling, but if + // the code is that bad and not thread-safe, it's trouble already. + delete this; + } + } + + S32 getNumRefs() const + { + const S32 currentVal = mRef.CurrentValue(); + return currentVal; + } private: - LLAtomicS32 mRef; + LLAtomicS32 mRef; }; /** @@ -143,12 +143,12 @@ private: */ inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLThreadSafeRefCount* p) { - p->unref(); + p->unref(); } /** @@ -157,12 +157,12 @@ inline void intrusive_ptr_release(LLThreadSafeRefCount* p) */ inline void intrusive_ptr_add_ref(LLRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLRefCount* p) { - p->unref(); + p->unref(); } #endif diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index d85a704376..15e47d6c89 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -1,4 +1,4 @@ -/** +/** * @file llrun.h * @author Phoenix * @date 2006-02-16 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,7 +45,7 @@ class LLRunnable; // LLDeferredChain isn't referenced at all. ////////////////////////////////////////////////////////////////////////////// -/** +/** * @class LLRunner * @brief This class manages a set of LLRunnable objects. * @@ -56,96 +56,96 @@ class LLRunnable; class LL_COMMON_API LLRunner { public: - /** - * @brief The pointer to a runnable. - */ - typedef std::shared_ptr run_ptr_t; - - /** - * @brief The handle for use in the API. - */ - typedef S64 run_handle_t; - - /** - * @brief Constructor. - */ - LLRunner(); - - /** - * @brief Destructor. - */ - ~LLRunner(); - - /** - * @brief Enumeration which specifies when to run. - */ - enum ERunSchedule - { - // The runnable will run in N seconds - RUN_IN, - - // The run every N seconds - RUN_EVERY, - - // A count of the run types - RUN_SCHEDULE_COUNT - }; - - /** - * @brief Run the runnables which are scheduled to run - * - * @return Returns the number of runnables run. - */ - size_t run(); - - /** - * @brief Add a runnable to the run list. - * - * The handle of the runnable is unique to each addition. If the - * same runnable is added a second time with the same or different - * schedule, this method will return a new handle. - * @param runnable The runnable to run() on schedule. - * @param schedule Specifies the run schedule. - * @param seconds When to run the runnable as interpreted by schedule. - * @return Returns the handle to the runnable. handle == 0 means failure. - */ - run_handle_t addRunnable( - run_ptr_t runnable, - ERunSchedule schedule, - F64 seconds); - - /** - * @brief Remove the specified runnable. - * - * @param handle The handle of the runnable to remove. - * @return Returns the pointer to the runnable removed which may - * be empty. - */ - run_ptr_t removeRunnable(run_handle_t handle); + /** + * @brief The pointer to a runnable. + */ + typedef std::shared_ptr run_ptr_t; + + /** + * @brief The handle for use in the API. + */ + typedef S64 run_handle_t; + + /** + * @brief Constructor. + */ + LLRunner(); + + /** + * @brief Destructor. + */ + ~LLRunner(); + + /** + * @brief Enumeration which specifies when to run. + */ + enum ERunSchedule + { + // The runnable will run in N seconds + RUN_IN, + + // The run every N seconds + RUN_EVERY, + + // A count of the run types + RUN_SCHEDULE_COUNT + }; + + /** + * @brief Run the runnables which are scheduled to run + * + * @return Returns the number of runnables run. + */ + size_t run(); + + /** + * @brief Add a runnable to the run list. + * + * The handle of the runnable is unique to each addition. If the + * same runnable is added a second time with the same or different + * schedule, this method will return a new handle. + * @param runnable The runnable to run() on schedule. + * @param schedule Specifies the run schedule. + * @param seconds When to run the runnable as interpreted by schedule. + * @return Returns the handle to the runnable. handle == 0 means failure. + */ + run_handle_t addRunnable( + run_ptr_t runnable, + ERunSchedule schedule, + F64 seconds); + + /** + * @brief Remove the specified runnable. + * + * @param handle The handle of the runnable to remove. + * @return Returns the pointer to the runnable removed which may + * be empty. + */ + run_ptr_t removeRunnable(run_handle_t handle); protected: - struct LLRunInfo - { - run_handle_t mHandle; - run_ptr_t mRunnable; - ERunSchedule mSchedule; - F64 mNextRunAt; - F64 mIncrement; - LLRunInfo( - run_handle_t handle, - run_ptr_t runnable, - ERunSchedule schedule, - F64 next_run_at, - F64 increment); - }; - typedef std::vector run_list_t; - run_list_t mRunOnce; - run_list_t mRunEvery; - run_handle_t mNextHandle; + struct LLRunInfo + { + run_handle_t mHandle; + run_ptr_t mRunnable; + ERunSchedule mSchedule; + F64 mNextRunAt; + F64 mIncrement; + LLRunInfo( + run_handle_t handle, + run_ptr_t runnable, + ERunSchedule schedule, + F64 next_run_at, + F64 increment); + }; + typedef std::vector run_list_t; + run_list_t mRunOnce; + run_list_t mRunEvery; + run_handle_t mNextHandle; }; -/** +/** * @class LLRunnable * @brief Abstract base class for running some scheduled process. * @@ -157,17 +157,17 @@ protected: class LL_COMMON_API LLRunnable { public: - LLRunnable(); - virtual ~LLRunnable(); - - /** - * @brief Do the process. - * - * This method will be called from the LLRunner according to - * @param runner The Runner which call run(). - * @param handle The handle this run instance is run under. - */ - virtual void run(LLRunner* runner, S64 handle) = 0; + LLRunnable(); + virtual ~LLRunnable(); + + /** + * @brief Do the process. + * + * This method will be called from the LLRunner according to + * @param runner The Runner which call run(). + * @param handle The handle this run instance is run under. + */ + virtual void run(LLRunner* runner, S64 handle) = 0; }; #endif // LL_LLRUN_H diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 9478dff871..196fd1eea8 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,25 +1,25 @@ -/** +/** * @file llstring.h * @brief String utility functions and std::string class. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -61,85 +61,85 @@ namespace std template<> struct char_traits { - typedef U16 char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - typedef mbstate_t state_type; - - static void - assign(char_type& __c1, const char_type& __c2) - { __c1 = __c2; } - - static bool - eq(const char_type& __c1, const char_type& __c2) - { return __c1 == __c2; } - - static bool - lt(const char_type& __c1, const char_type& __c2) - { return __c1 < __c2; } - - static int - compare(const char_type* __s1, const char_type* __s2, size_t __n) - { return memcmp(__s1, __s2, __n * sizeof(char_type)); } - - static size_t - length(const char_type* __s) - { - const char_type *cur_char = __s; - while (*cur_char != 0) - { - ++cur_char; - } - return cur_char - __s; - } - - static const char_type* - find(const char_type* __s, size_t __n, const char_type& __a) - { return static_cast(memchr(__s, __a, __n * sizeof(char_type))); } - - static char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memmove(__s1, __s2, __n * sizeof(char_type))); } - - static char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ - - static char_type* - assign(char_type* __s, size_t __n, char_type __a) - { - // This isn't right. - //return static_cast(memset(__s, __a, __n * sizeof(char_type))); - - // I don't think there's a standard 'memset' for 16-bit values. - // Do this the old-fashioned way. - - size_t __i; - for(__i = 0; __i < __n; __i++) - { - __s[__i] = __a; - } - return __s; - } - - static char_type - to_char_type(const int_type& __c) - { return static_cast(__c); } - - static int_type - to_int_type(const char_type& __c) - { return static_cast(__c); } - - static bool - eq_int_type(const int_type& __c1, const int_type& __c2) - { return __c1 == __c2; } - - static int_type - eof() { return static_cast(EOF); } - - static int_type - not_eof(const int_type& __c) + typedef U16 char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + typedef mbstate_t state_type; + + static void + assign(char_type& __c1, const char_type& __c2) + { __c1 = __c2; } + + static bool + eq(const char_type& __c1, const char_type& __c2) + { return __c1 == __c2; } + + static bool + lt(const char_type& __c1, const char_type& __c2) + { return __c1 < __c2; } + + static int + compare(const char_type* __s1, const char_type* __s2, size_t __n) + { return memcmp(__s1, __s2, __n * sizeof(char_type)); } + + static size_t + length(const char_type* __s) + { + const char_type *cur_char = __s; + while (*cur_char != 0) + { + ++cur_char; + } + return cur_char - __s; + } + + static const char_type* + find(const char_type* __s, size_t __n, const char_type& __a) + { return static_cast(memchr(__s, __a, __n * sizeof(char_type))); } + + static char_type* + move(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast(memmove(__s1, __s2, __n * sizeof(char_type))); } + + static char_type* + copy(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ + + static char_type* + assign(char_type* __s, size_t __n, char_type __a) + { + // This isn't right. + //return static_cast(memset(__s, __a, __n * sizeof(char_type))); + + // I don't think there's a standard 'memset' for 16-bit values. + // Do this the old-fashioned way. + + size_t __i; + for(__i = 0; __i < __n; __i++) + { + __s[__i] = __a; + } + return __s; + } + + static char_type + to_char_type(const int_type& __c) + { return static_cast(__c); } + + static int_type + to_int_type(const char_type& __c) + { return static_cast(__c); } + + static bool + eq_int_type(const int_type& __c1, const int_type& __c2) + { return __c1 == __c2; } + + static int_type + eof() { return static_cast(EOF); } + + static int_type + not_eof(const int_type& __c) { return (__c == eof()) ? 0 : __c; } }; }; @@ -148,72 +148,72 @@ struct char_traits class LL_COMMON_API LLStringOps { private: - static long sPacificTimeOffset; - static long sLocalTimeOffset; - static bool sPacificDaylightTime; + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; - static std::map datetimeToCodes; + static std::map datetimeToCodes; public: - static std::vector sWeekDayList; - static std::vector sWeekDayShortList; - static std::vector sMonthList; - static std::vector sMonthShortList; - static std::string sDayFormat; + static std::vector sWeekDayList; + static std::vector sWeekDayShortList; + static std::vector sMonthList; + static std::vector sMonthShortList; + static std::string sDayFormat; - static std::string sAM; - static std::string sPM; + static std::string sAM; + static std::string sPM; - static char toUpper(char elem) { return toupper((unsigned char)elem); } - static llwchar toUpper(llwchar elem) { return towupper(elem); } - - static char toLower(char elem) { return tolower((unsigned char)elem); } - static llwchar toLower(llwchar elem) { return towlower(elem); } + static char toUpper(char elem) { return toupper((unsigned char)elem); } + static llwchar toUpper(llwchar elem) { return towupper(elem); } - static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } - static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + static char toLower(char elem) { return tolower((unsigned char)elem); } + static llwchar toLower(llwchar elem) { return towlower(elem); } - static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } - static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } - static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } - static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } - static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } - static bool isDigit(llwchar a) { return iswdigit(a) != 0; } + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } - static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(a) != 0; } - static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } - static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } + static bool isPunct(llwchar a) { return iswpunct(a) != 0; } - static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } - static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } - static bool isEmoji(llwchar wch); + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } + static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - static S32 collate(const char* a, const char* b) { return strcoll(a, b); } - static S32 collate(const llwchar* a, const llwchar* b); + static bool isEmoji(llwchar wch); - static void setupDatetimeInfo(bool pacific_daylight_time); + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } + static S32 collate(const llwchar* a, const llwchar* b); - static void setupWeekDaysNames(const std::string& data); - static void setupWeekDaysShortNames(const std::string& data); - static void setupMonthNames(const std::string& data); - static void setupMonthShortNames(const std::string& data); - static void setupDayFormat(const std::string& data); + static void setupDatetimeInfo(bool pacific_daylight_time); + static void setupWeekDaysNames(const std::string& data); + static void setupWeekDaysShortNames(const std::string& data); + static void setupMonthNames(const std::string& data); + static void setupMonthShortNames(const std::string& data); + static void setupDayFormat(const std::string& data); - static long getPacificTimeOffset(void) { return sPacificTimeOffset;} - static long getLocalTimeOffset(void) { return sLocalTimeOffset;} - // Is the Pacific time zone (aka server time zone) - // currently in daylight savings time? - static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - static std::string getDatetimeCode (std::string key); + static long getPacificTimeOffset(void) { return sPacificTimeOffset;} + static long getLocalTimeOffset(void) { return sLocalTimeOffset;} + // Is the Pacific time zone (aka server time zone) + // currently in daylight savings time? + static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - // Express a value like 1234567 as "1.23M" + static std::string getDatetimeCode (std::string key); + + // Express a value like 1234567 as "1.23M" static std::string getReadableNumber(F64 num); }; @@ -230,216 +230,216 @@ LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); class LLFormatMapString { public: - LLFormatMapString() {}; - LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; - LLFormatMapString(const std::string& s) : mString(s) {}; - operator std::string() const { return mString; } - bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } - std::size_t length() const { return mString.length(); } - + LLFormatMapString() {}; + LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; + LLFormatMapString(const std::string& s) : mString(s) {}; + operator std::string() const { return mString; } + bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } + std::size_t length() const { return mString.length(); } + private: - std::string mString; + std::string mString; }; template class LLStringUtilBase { private: - static std::string sLocale; + static std::string sLocale; public: - typedef std::basic_string string_type; - typedef typename string_type::size_type size_type; - + typedef std::basic_string string_type; + typedef typename string_type::size_type size_type; + public: - ///////////////////////////////////////////////////////////////////////////////////////// - // Static Utility functions that operate on std::strings - - static const string_type null; - - typedef std::map format_map_t; - /// considers any sequence of delims as a single field separator - LL_COMMON_API static void getTokens(const string_type& instr, - std::vector& tokens, - const string_type& delims); - /// like simple scan overload, but returns scanned vector - static std::vector getTokens(const string_type& instr, - const string_type& delims); - /// add support for keep_delims and quotes (either could be empty string) - static void getTokens(const string_type& instr, - std::vector& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// like keep_delims-and-quotes overload, but returns scanned vector - static std::vector getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// add support for escapes (could be empty string) - static void getTokens(const string_type& instr, - std::vector& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - /// like escapes overload, but returns scanned vector - static std::vector getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - - LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); - LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); - LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); - LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); - LL_COMMON_API static void setLocale (std::string inLocale); - LL_COMMON_API static std::string getLocale (void); - - static bool isValidIndex(const string_type& string, size_type i) - { - return !string.empty() && (0 <= i) && (i <= string.size()); - } - - static bool contains(const string_type& string, T c, size_type i=0) - { - return string.find(c, i) != string_type::npos; - } - - static void trimHead(string_type& string); - static void trimTail(string_type& string); - static void trim(string_type& string) { trimHead(string); trimTail(string); } - static void truncate(string_type& string, size_type count); - - static void toUpper(string_type& string); - static void toLower(string_type& string); - - // True if this is the head of s. - static BOOL isHead( const string_type& string, const T* s ); - - /** - * @brief Returns true if string starts with substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool startsWith( - const string_type& string, - const string_type& substr); - - /** - * @brief Returns true if string ends in substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool endsWith( - const string_type& string, - const string_type& substr); - - /** - * get environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by return value == dflt - */ - static string_type getenv(const std::string& key, const string_type& dflt=""); - /** - * get optional environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by (! return value) - */ - static boost::optional getoptenv(const std::string& key); - - static void addCRLF(string_type& string); - static void removeCRLF(string_type& string); - static void removeWindowsCR(string_type& string); - - static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); - static void replaceNonstandardASCII( string_type& string, T replacement ); - static void replaceChar( string_type& string, T target, T replacement ); - static void replaceString( string_type& string, string_type target, string_type replacement ); - static string_type capitalize(const string_type& str); - static void capitalize(string_type& str); - - static BOOL containsNonprintable(const string_type& string); - static void stripNonprintable(string_type& string); - - /** - * Double-quote an argument string if needed, unless it's already - * double-quoted. Decide whether it's needed based on the presence of any - * character in @a triggers (default space or double-quote). If we quote - * it, escape any embedded double-quote with the @a escape string (default - * backslash). - * - * Passing triggers="" means always quote, unless it's already double-quoted. - */ - static string_type quote(const string_type& str, - const string_type& triggers=" \"", - const string_type& escape="\\"); - - /** - * @brief Unsafe way to make ascii characters. You should probably - * only call this when interacting with the host operating system. - * The 1 byte std::string does not work correctly. - * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII - * should work. - */ - static void _makeASCII(string_type& string); - - // Conversion to other data types - static BOOL convertToBOOL(const string_type& string, BOOL& value); - static BOOL convertToU8(const string_type& string, U8& value); - static BOOL convertToS8(const string_type& string, S8& value); - static BOOL convertToS16(const string_type& string, S16& value); - static BOOL convertToU16(const string_type& string, U16& value); - static BOOL convertToU32(const string_type& string, U32& value); - static BOOL convertToS32(const string_type& string, S32& value); - static BOOL convertToF32(const string_type& string, F32& value); - static BOOL convertToF64(const string_type& string, F64& value); - - ///////////////////////////////////////////////////////////////////////////////////////// - // Utility functions for working with char*'s and strings - - // Like strcmp but also handles empty strings. Uses - // current locale. - static S32 compareStrings(const T* lhs, const T* rhs); - static S32 compareStrings(const string_type& lhs, const string_type& rhs); - - // case insensitive version of above. Uses current locale on - // Win32, and falls back to a non-locale aware comparison on - // Linux. - static S32 compareInsensitive(const T* lhs, const T* rhs); - static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); - - // Case sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDict(const string_type& a, const string_type& b); - - // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDictInsensitive(const string_type& a, const string_type& b); - - // Puts compareDict() in a form appropriate for LL container classes to use for sorting. - static BOOL precedesDict( const string_type& a, const string_type& b ); - - // A replacement for strncpy. - // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds - // up to dst_size-1 characters of src. - static void copy(T* dst, const T* src, size_type dst_size); - - // Copies src into dst at a given offset. - static void copyInto(string_type& dst, const string_type& src, size_type offset); - - static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } - - -#ifdef _DEBUG - LL_COMMON_API static void testHarness(); + ///////////////////////////////////////////////////////////////////////////////////////// + // Static Utility functions that operate on std::strings + + static const string_type null; + + typedef std::map format_map_t; + /// considers any sequence of delims as a single field separator + LL_COMMON_API static void getTokens(const string_type& instr, + std::vector& tokens, + const string_type& delims); + /// like simple scan overload, but returns scanned vector + static std::vector getTokens(const string_type& instr, + const string_type& delims); + /// add support for keep_delims and quotes (either could be empty string) + static void getTokens(const string_type& instr, + std::vector& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// like keep_delims-and-quotes overload, but returns scanned vector + static std::vector getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// add support for escapes (could be empty string) + static void getTokens(const string_type& instr, + std::vector& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + /// like escapes overload, but returns scanned vector + static std::vector getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + + LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); + LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); + LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); + LL_COMMON_API static void setLocale (std::string inLocale); + LL_COMMON_API static std::string getLocale (void); + + static bool isValidIndex(const string_type& string, size_type i) + { + return !string.empty() && (0 <= i) && (i <= string.size()); + } + + static bool contains(const string_type& string, T c, size_type i=0) + { + return string.find(c, i) != string_type::npos; + } + + static void trimHead(string_type& string); + static void trimTail(string_type& string); + static void trim(string_type& string) { trimHead(string); trimTail(string); } + static void truncate(string_type& string, size_type count); + + static void toUpper(string_type& string); + static void toLower(string_type& string); + + // True if this is the head of s. + static BOOL isHead( const string_type& string, const T* s ); + + /** + * @brief Returns true if string starts with substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool startsWith( + const string_type& string, + const string_type& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const string_type& string, + const string_type& substr); + + /** + * get environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by return value == dflt + */ + static string_type getenv(const std::string& key, const string_type& dflt=""); + /** + * get optional environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by (! return value) + */ + static boost::optional getoptenv(const std::string& key); + + static void addCRLF(string_type& string); + static void removeCRLF(string_type& string); + static void removeWindowsCR(string_type& string); + + static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); + static void replaceNonstandardASCII( string_type& string, T replacement ); + static void replaceChar( string_type& string, T target, T replacement ); + static void replaceString( string_type& string, string_type target, string_type replacement ); + static string_type capitalize(const string_type& str); + static void capitalize(string_type& str); + + static BOOL containsNonprintable(const string_type& string); + static void stripNonprintable(string_type& string); + + /** + * Double-quote an argument string if needed, unless it's already + * double-quoted. Decide whether it's needed based on the presence of any + * character in @a triggers (default space or double-quote). If we quote + * it, escape any embedded double-quote with the @a escape string (default + * backslash). + * + * Passing triggers="" means always quote, unless it's already double-quoted. + */ + static string_type quote(const string_type& str, + const string_type& triggers=" \"", + const string_type& escape="\\"); + + /** + * @brief Unsafe way to make ascii characters. You should probably + * only call this when interacting with the host operating system. + * The 1 byte std::string does not work correctly. + * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII + * should work. + */ + static void _makeASCII(string_type& string); + + // Conversion to other data types + static BOOL convertToBOOL(const string_type& string, BOOL& value); + static BOOL convertToU8(const string_type& string, U8& value); + static BOOL convertToS8(const string_type& string, S8& value); + static BOOL convertToS16(const string_type& string, S16& value); + static BOOL convertToU16(const string_type& string, U16& value); + static BOOL convertToU32(const string_type& string, U32& value); + static BOOL convertToS32(const string_type& string, S32& value); + static BOOL convertToF32(const string_type& string, F32& value); + static BOOL convertToF64(const string_type& string, F64& value); + + ///////////////////////////////////////////////////////////////////////////////////////// + // Utility functions for working with char*'s and strings + + // Like strcmp but also handles empty strings. Uses + // current locale. + static S32 compareStrings(const T* lhs, const T* rhs); + static S32 compareStrings(const string_type& lhs, const string_type& rhs); + + // case insensitive version of above. Uses current locale on + // Win32, and falls back to a non-locale aware comparison on + // Linux. + static S32 compareInsensitive(const T* lhs, const T* rhs); + static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); + + // Case sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDict(const string_type& a, const string_type& b); + + // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDictInsensitive(const string_type& a, const string_type& b); + + // Puts compareDict() in a form appropriate for LL container classes to use for sorting. + static BOOL precedesDict( const string_type& a, const string_type& b ); + + // A replacement for strncpy. + // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds + // up to dst_size-1 characters of src. + static void copy(T* dst, const T* src, size_type dst_size); + + // Copies src into dst at a given offset. + static void copyInto(string_type& dst, const string_type& src, size_type offset); + + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + +#ifdef _DEBUG + LL_COMMON_API static void testHarness(); #endif private: - LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector& tokens); + LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector& tokens); }; template const std::basic_string LLStringUtilBase::null; @@ -455,18 +455,18 @@ typedef std::basic_string LLWString; class LLStringExplicit : public std::string { public: - explicit LLStringExplicit(const char* s) : std::string(s) {} - LLStringExplicit(const std::string& s) : std::string(s) {} - LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} + explicit LLStringExplicit(const char* s) : std::string(s) {} + LLStringExplicit(const std::string& s) : std::string(s) {} + LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} }; struct LLDictionaryLess { public: - bool operator()(const std::string& a, const std::string& b) const - { - return (LLStringUtil::precedesDict(a, b) ? true : false); - } + bool operator()(const std::string& a, const std::string& b) const + { + return (LLStringUtil::precedesDict(a, b) ? true : false); + } }; @@ -483,10 +483,10 @@ public: * @return a copy of in string minus the trailing count bytes. */ inline std::string chop_tail_copy( - const std::string& in, - std::string::size_type count) + const std::string& in, + std::string::size_type count) { - return std::string(in, 0, in.length() - count); + return std::string(in, 0, in.length() - count); } /** @@ -706,10 +706,10 @@ ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_u inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} // Length of this UTF32 string in bytes when transformed to UTF8 -LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); // Length in bytes of this wide char in a UTF8 string -LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); LL_COMMON_API std::string wchar_utf8_preview(const llwchar wc); @@ -726,7 +726,7 @@ LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wst /** * @brief Properly truncate a utf8 string to a maximum byte count. - * + * * The returned string may be less than max_len if the truncation * happens in the middle of a glyph. If max_len is longer than the * string passed in, the return value == utf8str. @@ -739,8 +739,8 @@ LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); LL_COMMON_API S32 utf8str_compare_insensitive( - const std::string& lhs, - const std::string& rhs); + const std::string& lhs, + const std::string& rhs); /** * @brief Properly truncate a utf8 string to a maximum character count. @@ -761,14 +761,14 @@ LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, co * @param replace_char The wchar which is written on replace */ LL_COMMON_API std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char); + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char); LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); // Hack - used for evil notecards. -LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); @@ -874,52 +874,52 @@ LL_COMMON_API boost::optional llstring_getoptenv(const std::string */ namespace LLStringFn { - /** - * @brief Replace all non-printable characters with replacement in - * string. - * NOTE - this will zap non-ascii - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_in_ascii( - std::basic_string& string, - char replacement); - - - /** - * @brief Replace all non-printable characters and pipe characters - * with replacement in a string. - * NOTE - this will zap non-ascii - * - * @param [in,out] the string to modify. out value is the string - * with zero non-printable characters and zero pipe characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, - char replacement); - - - /** - * @brief Remove all characters that are not allowed in XML 1.0. - * Returns a copy of the string with those characters removed. - * Works with US ASCII and UTF-8 encoded strings. JC - */ - LL_COMMON_API std::string strip_invalid_xml(const std::string& input); - - - /** - * @brief Replace all control characters (0 <= c < 0x20) with replacement in - * string. This is safe for utf-8 - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_ascii_controlchars( - std::basic_string& string, - char replacement); + /** + * @brief Replace all non-printable characters with replacement in + * string. + * NOTE - this will zap non-ascii + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_in_ascii( + std::basic_string& string, + char replacement); + + + /** + * @brief Replace all non-printable characters and pipe characters + * with replacement in a string. + * NOTE - this will zap non-ascii + * + * @param [in,out] the string to modify. out value is the string + * with zero non-printable characters and zero pipe characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, + char replacement); + + + /** + * @brief Remove all characters that are not allowed in XML 1.0. + * Returns a copy of the string with those characters removed. + * Works with US ASCII and UTF-8 encoded strings. JC + */ + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + + /** + * @brief Replace all control characters (0 <= c < 0x20) with replacement in + * string. This is safe for utf-8 + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_ascii_controlchars( + std::basic_string& string, + char replacement); } //////////////////////////////////////////////////////////// @@ -934,36 +934,36 @@ template std::vector::string_type> LLStringUtilBase::getTokens(const string_type& instr, const string_type& delims) { - std::vector tokens; - getTokens(instr, tokens, delims); - return tokens; + std::vector tokens; + getTokens(instr, tokens, delims); + return tokens; } // static template std::vector::string_type> LLStringUtilBase::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes) { - std::vector tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes); - return tokens; + std::vector tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes); + return tokens; } // static template std::vector::string_type> LLStringUtilBase::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes) -{ - std::vector tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); - return tokens; + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes) +{ + std::vector tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); + return tokens; } namespace LLStringUtilBaseImpl @@ -979,62 +979,62 @@ namespace LLStringUtilBaseImpl template struct InString { - typedef std::basic_string string_type; - typedef typename string_type::const_iterator const_iterator; - - InString(const_iterator b, const_iterator e): - mIter(b), - mEnd(e) - {} - virtual ~InString() {} - - bool done() const { return mIter == mEnd; } - /// Is the current character (*mIter) escaped? This implementation can - /// answer trivially because it doesn't support escapes. - virtual bool escaped() const { return false; } - /// Obtain the current character and advance @c mIter. - virtual T next() { return *mIter++; } - /// Does the current character match specified character? - virtual bool is(T ch) const { return (! done()) && *mIter == ch; } - /// Is the current character any one of the specified characters? - virtual bool oneof(const string_type& delims) const - { - return (! done()) && LLStringUtilBase::contains(delims, *mIter); - } - - /** - * Scan forward from @from until either @a delim or end. This is primarily - * useful for processing quoted substrings. - * - * If we do see @a delim, append everything from @from until (excluding) - * @a delim to @a into, advance @c mIter to skip @a delim, and return @c - * true. - * - * If we do not see @a delim, do not alter @a into or @c mIter and return - * @c false. Do not pass GO, do not collect $200. - * - * @note The @c false case described above implements normal getTokens() - * treatment of an unmatched open quote: treat the quote character as if - * escaped, that is, simply collect it as part of the current token. Other - * plausible behaviors directly affect the way getTokens() deals with an - * unmatched quote: e.g. throwing an exception to treat it as an error, or - * assuming a close quote beyond end of string (in which case return @c - * true). - */ - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - const_iterator found = std::find(from, mEnd, delim); - // If we didn't find delim, change nothing, just tell caller. - if (found == mEnd) - return false; - // Found delim! Append everything between from and found. - into.append(from, found); - // advance past delim in input - mIter = found + 1; - return true; - } - - const_iterator mIter, mEnd; + typedef std::basic_string string_type; + typedef typename string_type::const_iterator const_iterator; + + InString(const_iterator b, const_iterator e): + mIter(b), + mEnd(e) + {} + virtual ~InString() {} + + bool done() const { return mIter == mEnd; } + /// Is the current character (*mIter) escaped? This implementation can + /// answer trivially because it doesn't support escapes. + virtual bool escaped() const { return false; } + /// Obtain the current character and advance @c mIter. + virtual T next() { return *mIter++; } + /// Does the current character match specified character? + virtual bool is(T ch) const { return (! done()) && *mIter == ch; } + /// Is the current character any one of the specified characters? + virtual bool oneof(const string_type& delims) const + { + return (! done()) && LLStringUtilBase::contains(delims, *mIter); + } + + /** + * Scan forward from @from until either @a delim or end. This is primarily + * useful for processing quoted substrings. + * + * If we do see @a delim, append everything from @from until (excluding) + * @a delim to @a into, advance @c mIter to skip @a delim, and return @c + * true. + * + * If we do not see @a delim, do not alter @a into or @c mIter and return + * @c false. Do not pass GO, do not collect $200. + * + * @note The @c false case described above implements normal getTokens() + * treatment of an unmatched open quote: treat the quote character as if + * escaped, that is, simply collect it as part of the current token. Other + * plausible behaviors directly affect the way getTokens() deals with an + * unmatched quote: e.g. throwing an exception to treat it as an error, or + * assuming a close quote beyond end of string (in which case return @c + * true). + */ + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + const_iterator found = std::find(from, mEnd, delim); + // If we didn't find delim, change nothing, just tell caller. + if (found == mEnd) + return false; + // Found delim! Append everything between from and found. + into.append(from, found); + // advance past delim in input + mIter = found + 1; + return true; + } + + const_iterator mIter, mEnd; }; /// InString subclass that handles escape characters @@ -1042,177 +1042,177 @@ template class InEscString: public InString { public: - typedef InString super; - typedef typename super::string_type string_type; - typedef typename super::const_iterator const_iterator; - using super::done; - using super::mIter; - using super::mEnd; - - InEscString(const_iterator b, const_iterator e, const string_type& escapes): - super(b, e), - mEscapes(escapes) - { - // Even though we've already initialized 'mIter' via our base-class - // constructor, set it again to check for initial escape char. - setiter(b); - } - - /// This implementation uses the answer cached by setiter(). - virtual bool escaped() const { return mIsEsc; } - virtual T next() - { - // If we're looking at the escape character of an escape sequence, - // skip that character. This is the one time we can modify 'mIter' - // without using setiter: for this one case we DO NOT CARE if the - // escaped character is itself an escape. - if (mIsEsc) - ++mIter; - // If we were looking at an escape character, this is the escaped - // character; otherwise it's just the next character. - T result(*mIter); - // Advance mIter, checking for escape sequence. - setiter(mIter + 1); - return result; - } - - virtual bool is(T ch) const - { - // Like base-class is(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && *mIter == ch; - } - - virtual bool oneof(const string_type& delims) const - { - // Like base-class oneof(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && LLStringUtilBase::contains(delims, *mIter); - } - - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - // Deal with escapes in the characters we collect; that is, an escaped - // character must become just that character without the preceding - // escape. Collect characters in a separate string rather than - // directly appending to 'into' in case we do not find delim, in which - // case we're supposed to leave 'into' unmodified. - string_type collected; - // For scanning purposes, we're going to work directly with 'mIter'. - // Save its current value in case we fail to see delim. - const_iterator save_iter(mIter); - // Okay, set 'mIter', checking for escape. - setiter(from); - while (! done()) - { - // If we see an unescaped delim, stop and report success. - if ((! mIsEsc) && *mIter == delim) - { - // Append collected chars to 'into'. - into.append(collected); - // Don't forget to advance 'mIter' past delim. - setiter(mIter + 1); - return true; - } - // We're not at end, and either we're not looking at delim or it's - // escaped. Collect this character and keep going. - collected.push_back(next()); - } - // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell - // caller. - setiter(save_iter); - return false; - } + typedef InString super; + typedef typename super::string_type string_type; + typedef typename super::const_iterator const_iterator; + using super::done; + using super::mIter; + using super::mEnd; + + InEscString(const_iterator b, const_iterator e, const string_type& escapes): + super(b, e), + mEscapes(escapes) + { + // Even though we've already initialized 'mIter' via our base-class + // constructor, set it again to check for initial escape char. + setiter(b); + } + + /// This implementation uses the answer cached by setiter(). + virtual bool escaped() const { return mIsEsc; } + virtual T next() + { + // If we're looking at the escape character of an escape sequence, + // skip that character. This is the one time we can modify 'mIter' + // without using setiter: for this one case we DO NOT CARE if the + // escaped character is itself an escape. + if (mIsEsc) + ++mIter; + // If we were looking at an escape character, this is the escaped + // character; otherwise it's just the next character. + T result(*mIter); + // Advance mIter, checking for escape sequence. + setiter(mIter + 1); + return result; + } + + virtual bool is(T ch) const + { + // Like base-class is(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && *mIter == ch; + } + + virtual bool oneof(const string_type& delims) const + { + // Like base-class oneof(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && LLStringUtilBase::contains(delims, *mIter); + } + + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + // Deal with escapes in the characters we collect; that is, an escaped + // character must become just that character without the preceding + // escape. Collect characters in a separate string rather than + // directly appending to 'into' in case we do not find delim, in which + // case we're supposed to leave 'into' unmodified. + string_type collected; + // For scanning purposes, we're going to work directly with 'mIter'. + // Save its current value in case we fail to see delim. + const_iterator save_iter(mIter); + // Okay, set 'mIter', checking for escape. + setiter(from); + while (! done()) + { + // If we see an unescaped delim, stop and report success. + if ((! mIsEsc) && *mIter == delim) + { + // Append collected chars to 'into'. + into.append(collected); + // Don't forget to advance 'mIter' past delim. + setiter(mIter + 1); + return true; + } + // We're not at end, and either we're not looking at delim or it's + // escaped. Collect this character and keep going. + collected.push_back(next()); + } + // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell + // caller. + setiter(save_iter); + return false; + } private: - void setiter(const_iterator i) - { - mIter = i; - - // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively - // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches - // contains(mEscapes, *mIter). - - // We're looking at an escaped char if we're not already at end (that - // is, *mIter is even meaningful); if *mIter is in fact one of the - // specified escape characters; and if there's one more character - // following it. That is, if an escape character is the very last - // character of the input string, it loses its special meaning. - mIsEsc = (! done()) && - LLStringUtilBase::contains(mEscapes, *mIter) && - (mIter+1) != mEnd; - } - - const string_type mEscapes; - bool mIsEsc; + void setiter(const_iterator i) + { + mIter = i; + + // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively + // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches + // contains(mEscapes, *mIter). + + // We're looking at an escaped char if we're not already at end (that + // is, *mIter is even meaningful); if *mIter is in fact one of the + // specified escape characters; and if there's one more character + // following it. That is, if an escape character is the very last + // character of the input string, it loses its special meaning. + mIsEsc = (! done()) && + LLStringUtilBase::contains(mEscapes, *mIter) && + (mIter+1) != mEnd; + } + + const string_type mEscapes; + bool mIsEsc; }; /// getTokens() implementation based on InString concept template void getTokens(INSTRING& instr, std::vector& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) -{ - // There are times when we want to match either drop_delims or - // keep_delims. Concatenate them up front to speed things up. - string_type all_delims(drop_delims + keep_delims); - // no tokens yet - tokens.clear(); - - // try for another token - while (! instr.done()) - { - // scan past any drop_delims - while (instr.oneof(drop_delims)) - { - // skip this drop_delim - instr.next(); - // but if that was the end of the string, done - if (instr.done()) - return; - } - // found the start of another token: make a slot for it - tokens.push_back(string_type()); - if (instr.oneof(keep_delims)) - { - // *iter is a keep_delim, a token of exactly 1 character. Append - // that character to the new token and proceed. - tokens.back().push_back(instr.next()); - continue; - } - // Here we have a non-delimiter token, which might consist of a mix of - // quoted and unquoted parts. Use bash rules for quoting: you can - // embed a quoted substring in the midst of an unquoted token (e.g. - // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together - // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge - // from bash in that bash considers an unmatched quote an error. Our - // param signature doesn't allow for errors, so just pretend it's not - // a quote and embed it. - // At this level, keep scanning until we hit the next delimiter of - // either type (drop_delims or keep_delims). - while (! instr.oneof(all_delims)) - { - // If we're looking at an open quote, search forward for - // a close quote, collecting characters along the way. - if (instr.oneof(quotes) && - instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) - { - // collect_until is cleverly designed to do exactly what we - // need here. No further action needed if it returns true. - } - else - { - // Either *iter isn't a quote, or there's no matching close - // quote: in other words, just an ordinary char. Append it to - // current token. - tokens.back().push_back(instr.next()); - } - // having scanned that segment of this token, if we've reached the - // end of the string, we're done - if (instr.done()) - return; - } - } + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) +{ + // There are times when we want to match either drop_delims or + // keep_delims. Concatenate them up front to speed things up. + string_type all_delims(drop_delims + keep_delims); + // no tokens yet + tokens.clear(); + + // try for another token + while (! instr.done()) + { + // scan past any drop_delims + while (instr.oneof(drop_delims)) + { + // skip this drop_delim + instr.next(); + // but if that was the end of the string, done + if (instr.done()) + return; + } + // found the start of another token: make a slot for it + tokens.push_back(string_type()); + if (instr.oneof(keep_delims)) + { + // *iter is a keep_delim, a token of exactly 1 character. Append + // that character to the new token and proceed. + tokens.back().push_back(instr.next()); + continue; + } + // Here we have a non-delimiter token, which might consist of a mix of + // quoted and unquoted parts. Use bash rules for quoting: you can + // embed a quoted substring in the midst of an unquoted token (e.g. + // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together + // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge + // from bash in that bash considers an unmatched quote an error. Our + // param signature doesn't allow for errors, so just pretend it's not + // a quote and embed it. + // At this level, keep scanning until we hit the next delimiter of + // either type (drop_delims or keep_delims). + while (! instr.oneof(all_delims)) + { + // If we're looking at an open quote, search forward for + // a close quote, collecting characters along the way. + if (instr.oneof(quotes) && + instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) + { + // collect_until is cleverly designed to do exactly what we + // need here. No further action needed if it returns true. + } + else + { + // Either *iter isn't a quote, or there's no matching close + // quote: in other words, just an ordinary char. Append it to + // current token. + tokens.back().push_back(instr.next()); + } + // having scanned that segment of this token, if we've reached the + // end of the string, we're done + if (instr.done()) + return; + } + } } } // namespace LLStringUtilBaseImpl @@ -1220,256 +1220,256 @@ void getTokens(INSTRING& instr, std::vector& tokens, // static template void LLStringUtilBase::getTokens(const string_type& string, std::vector& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) { - // Because this overload doesn't support escapes, use simple InString to - // manage input range. - LLStringUtilBaseImpl::InString instring(string.begin(), string.end()); - LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); + // Because this overload doesn't support escapes, use simple InString to + // manage input range. + LLStringUtilBaseImpl::InString instring(string.begin(), string.end()); + LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); } // static template void LLStringUtilBase::getTokens(const string_type& string, std::vector& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes, const string_type& escapes) -{ - // This overload must deal with escapes. Delegate that to InEscString - // (unless there ARE no escapes). - std::unique_ptr< LLStringUtilBaseImpl::InString > instrp; - if (escapes.empty()) - instrp.reset(new LLStringUtilBaseImpl::InString(string.begin(), string.end())); - else - instrp.reset(new LLStringUtilBaseImpl::InEscString(string.begin(), string.end(), escapes)); - LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes, const string_type& escapes) +{ + // This overload must deal with escapes. Delegate that to InEscString + // (unless there ARE no escapes). + std::unique_ptr< LLStringUtilBaseImpl::InString > instrp; + if (escapes.empty()) + instrp.reset(new LLStringUtilBaseImpl::InString(string.begin(), string.end())); + else + instrp.reset(new LLStringUtilBaseImpl::InEscString(string.begin(), string.end(), escapes)); + LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); } // static -template +template S32 LLStringUtilBase::compareStrings(const T* lhs, const T* rhs) -{ - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0]) - { - result = -1; - } - else - { - result = LLStringOps::collate(lhs, rhs); - } - return result; +{ + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0]) + { + result = -1; + } + else + { + result = LLStringOps::collate(lhs, rhs); + } + return result; } -//static -template +//static +template S32 LLStringUtilBase::compareStrings(const string_type& lhs, const string_type& rhs) { - return LLStringOps::collate(lhs.c_str(), rhs.c_str()); + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); } // static -template +template S32 LLStringUtilBase::compareInsensitive(const T* lhs, const T* rhs ) { - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0] ) - { - result = -1; - } - else - { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase::toUpper(lhs_string); - LLStringUtilBase::toUpper(rhs_string); - result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); - } - return result; + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0] ) + { + result = -1; + } + else + { + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase::toUpper(lhs_string); + LLStringUtilBase::toUpper(rhs_string); + result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + } + return result; } -//static -template +//static +template S32 LLStringUtilBase::compareInsensitive(const string_type& lhs, const string_type& rhs) { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase::toUpper(lhs_string); - LLStringUtilBase::toUpper(rhs_string); - return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase::toUpper(lhs_string); + LLStringUtilBase::toUpper(rhs_string); + return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); } // Case sensitive comparison with good handling of numbers. Does not use current locale. // a.k.a. strdictcmp() -//static +//static template S32 LLStringUtilBase::compareDict(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - S32 bias = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( bias==0 ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } - }else{ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai S32 LLStringUtilBase::compareDictInsensitive(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai +// static +template BOOL LLStringUtilBase::precedesDict( const string_type& a, const string_type& b ) { - if( a.size() && b.size() ) - { - return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); - } - else - { - return (!b.empty()); - } + if( a.size() && b.size() ) + { + return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); + } + else + { + return (!b.empty()); + } } //static -template -void LLStringUtilBase::toUpper(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toUpper); - } +template +void LLStringUtilBase::toUpper(string_type& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toUpper); + } } //static -template +template void LLStringUtilBase::toLower(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toLower); - } +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toLower); + } } //static -template +template void LLStringUtilBase::trimHead(string_type& string) -{ - if( !string.empty() ) - { - size_type i = 0; - while( i < string.length() && LLStringOps::isSpace( string[i] ) ) - { - i++; - } - string.erase(0, i); - } +{ + if( !string.empty() ) + { + size_type i = 0; + while( i < string.length() && LLStringOps::isSpace( string[i] ) ) + { + i++; + } + string.erase(0, i); + } } //static -template +template void LLStringUtilBase::trimTail(string_type& string) -{ - if( string.size() ) - { - size_type len = string.length(); - size_type i = len; - while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) - { - i--; - } - - string.erase( i, len - i ); - } +{ + if( string.size() ) + { + size_type len = string.length(); + size_type i = len; + while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) + { + i--; + } + + string.erase( i, len - i ); + } } @@ -1478,67 +1478,67 @@ void LLStringUtilBase::trimTail(string_type& string) template void LLStringUtilBase::addCRLF(string_type& string) { - const T LF = 10; - const T CR = 13; - - // Count the number of line feeds - size_type count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len; i++ ) - { - if( string[i] == LF ) - { - count++; - } - } - - // Insert a carriage return before each line feed - if( count ) - { - size_type size = len + count; - T *t = new T[size]; - size_type j = 0; - for( i = 0; i < len; ++i ) - { - if( string[i] == LF ) - { - t[j] = CR; - ++j; - } - t[j] = string[i]; - ++j; - } - - string.assign(t, size); - delete[] t; - } + const T LF = 10; + const T CR = 13; + + // Count the number of line feeds + size_type count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len; i++ ) + { + if( string[i] == LF ) + { + count++; + } + } + + // Insert a carriage return before each line feed + if( count ) + { + size_type size = len + count; + T *t = new T[size]; + size_type j = 0; + for( i = 0; i < len; ++i ) + { + if( string[i] == LF ) + { + t[j] = CR; + ++j; + } + t[j] = string[i]; + ++j; + } + + string.assign(t, size); + delete[] t; + } } // Remove all carriage returns //static -template +template void LLStringUtilBase::removeCRLF(string_type& string) { - const T CR = 13; - - size_type cr_count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len - cr_count; i++ ) - { - if( string[i+cr_count] == CR ) - { - cr_count++; - } - - string[i] = string[i+cr_count]; - } - string.erase(i, cr_count); + const T CR = 13; + + size_type cr_count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len - cr_count; i++ ) + { + if( string[i+cr_count] == CR ) + { + cr_count++; + } + + string[i] = string[i+cr_count]; + } + string.erase(i, cr_count); } //static -template +template void LLStringUtilBase::removeWindowsCR(string_type& string) { if (string.empty()) @@ -1567,269 +1567,269 @@ void LLStringUtilBase::removeWindowsCR(string_type& string) template void LLStringUtilBase::replaceChar( string_type& string, T target, T replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string[found_pos] = replacement; - found_pos++; // avoid infinite defeat if target == replacement - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } } //static -template +template void LLStringUtilBase::replaceString( string_type& string, string_type target, string_type replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string.replace( found_pos, target.length(), replacement ); - found_pos += replacement.length(); // avoid infinite defeat if replacement contains target - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } } //static -template +template void LLStringUtilBase::replaceNonstandardASCII( string_type& string, T replacement ) { - const char LF = 10; - const S8 MIN = 32; -// const S8 MAX = 127; - - size_type len = string.size(); - for( size_type i = 0; i < len; i++ ) - { - // No need to test MAX < mText[i] because we treat mText[i] as a signed char, - // which has a max value of 127. - if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) - { - string[i] = replacement; - } - } + const char LF = 10; + const S8 MIN = 32; +// const S8 MAX = 127; + + size_type len = string.size(); + for( size_type i = 0; i < len; i++ ) + { + // No need to test MAX < mText[i] because we treat mText[i] as a signed char, + // which has a max value of 127. + if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) + { + string[i] = replacement; + } + } } //static -template +template void LLStringUtilBase::replaceTabsWithSpaces( string_type& str, size_type spaces_per_tab ) { - const T TAB = '\t'; - const T SPACE = ' '; - - string_type out_str; - // Replace tabs with spaces - for (size_type i = 0; i < str.length(); i++) - { - if (str[i] == TAB) - { - for (size_type j = 0; j < spaces_per_tab; j++) - out_str += SPACE; - } - else - { - out_str += str[i]; - } - } - str = out_str; + const T TAB = '\t'; + const T SPACE = ' '; + + string_type out_str; + // Replace tabs with spaces + for (size_type i = 0; i < str.length(); i++) + { + if (str[i] == TAB) + { + for (size_type j = 0; j < spaces_per_tab; j++) + out_str += SPACE; + } + else + { + out_str += str[i]; + } + } + str = out_str; } //static template std::basic_string LLStringUtilBase::capitalize(const string_type& str) { - string_type result(str); - capitalize(result); - return result; + string_type result(str); + capitalize(result); + return result; } //static template void LLStringUtilBase::capitalize(string_type& str) { - if (str.size()) - { - auto last = str[0] = toupper(str[0]); - for (U32 i = 1; i < str.size(); ++i) - { - last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; - } - } + if (str.size()) + { + auto last = str[0] = toupper(str[0]); + for (U32 i = 1; i < str.size(); ++i) + { + last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; + } + } } //static -template +template BOOL LLStringUtilBase::containsNonprintable(const string_type& string) { - const char MIN = 32; - BOOL rv = FALSE; - for (size_type i = 0; i < string.size(); i++) - { - if(string[i] < MIN) - { - rv = TRUE; - break; - } - } - return rv; + const char MIN = 32; + BOOL rv = FALSE; + for (size_type i = 0; i < string.size(); i++) + { + if(string[i] < MIN) + { + rv = TRUE; + break; + } + } + return rv; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm //static -template +template void LLStringUtilBase::stripNonprintable(string_type& string) { - const char MIN = 32; - size_type j = 0; - if (string.empty()) - { - return; - } - size_t src_size = string.size(); - char* c_string = new char[src_size + 1]; - if(c_string == NULL) - { - return; - } - copy(c_string, string.c_str(), src_size+1); - char* write_head = &c_string[0]; - for (size_type i = 0; i < src_size; i++) - { - char* read_head = &string[i]; - write_head = &c_string[j]; - if(!(*read_head < MIN)) - { - *write_head = *read_head; - ++j; - } - } - c_string[j]= '\0'; - string = c_string; - delete []c_string; + const char MIN = 32; + size_type j = 0; + if (string.empty()) + { + return; + } + size_t src_size = string.size(); + char* c_string = new char[src_size + 1]; + if(c_string == NULL) + { + return; + } + copy(c_string, string.c_str(), src_size+1); + char* write_head = &c_string[0]; + for (size_type i = 0; i < src_size; i++) + { + char* read_head = &string[i]; + write_head = &c_string[j]; + if(!(*read_head < MIN)) + { + *write_head = *read_head; + ++j; + } + } + c_string[j]= '\0'; + string = c_string; + delete []c_string; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm template std::basic_string LLStringUtilBase::quote(const string_type& str, - const string_type& triggers, - const string_type& escape) -{ - size_type len(str.length()); - // If the string is already quoted, assume user knows what s/he's doing. - if (len >= 2 && str[0] == '"' && str[len-1] == '"') - { - return str; - } - - // Not already quoted: do we need to? triggers.empty() is a special case - // meaning "always quote." - if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) - { - // no trigger characters, don't bother quoting - return str; - } - - // For whatever reason, we must quote this string. - string_type result; - result.push_back('"'); - for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) - { - if (*ci == '"') - { - result.append(escape); - } - result.push_back(*ci); - } - result.push_back('"'); - return result; + const string_type& triggers, + const string_type& escape) +{ + size_type len(str.length()); + // If the string is already quoted, assume user knows what s/he's doing. + if (len >= 2 && str[0] == '"' && str[len-1] == '"') + { + return str; + } + + // Not already quoted: do we need to? triggers.empty() is a special case + // meaning "always quote." + if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) + { + // no trigger characters, don't bother quoting + return str; + } + + // For whatever reason, we must quote this string. + string_type result; + result.push_back('"'); + for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) + { + if (*ci == '"') + { + result.append(escape); + } + result.push_back(*ci); + } + result.push_back('"'); + return result; } -template +template void LLStringUtilBase::_makeASCII(string_type& string) { - // Replace non-ASCII chars with LL_UNKNOWN_CHAR - for (size_type i = 0; i < string.length(); i++) - { - if (string[i] > 0x7f) - { - string[i] = LL_UNKNOWN_CHAR; - } - } + // Replace non-ASCII chars with LL_UNKNOWN_CHAR + for (size_type i = 0; i < string.length(); i++) + { + if (string[i] > 0x7f) + { + string[i] = LL_UNKNOWN_CHAR; + } + } } // static -template +template void LLStringUtilBase::copy( T* dst, const T* src, size_type dst_size ) { - if( dst_size > 0 ) - { - size_type min_len = 0; - if( src ) - { - min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ - memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ - } - dst[min_len] = '\0'; - } + if( dst_size > 0 ) + { + size_type min_len = 0; + if( src ) + { + min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ + memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ + } + dst[min_len] = '\0'; + } } // static -template +template void LLStringUtilBase::copyInto(string_type& dst, const string_type& src, size_type offset) { - if ( offset == dst.length() ) - { - // special case - append to end of string and avoid expensive - // (when strings are large) string manipulations - dst += src; - } - else - { - string_type tail = dst.substr(offset); - - dst = dst.substr(0, offset); - dst += src; - dst += tail; - }; + if ( offset == dst.length() ) + { + // special case - append to end of string and avoid expensive + // (when strings are large) string manipulations + dst += src; + } + else + { + string_type tail = dst.substr(offset); + + dst = dst.substr(0, offset); + dst += src; + dst += tail; + }; } // True if this is the head of s. //static -template -BOOL LLStringUtilBase::isHead( const string_type& string, const T* s ) -{ - if( string.empty() ) - { - // Early exit - return FALSE; - } - else - { - return (strncmp( s, string.c_str(), string.size() ) == 0); - } +template +BOOL LLStringUtilBase::isHead( const string_type& string, const T* s ) +{ + if( string.empty() ) + { + // Early exit + return FALSE; + } + else + { + return (strncmp( s, string.c_str(), string.size() ) == 0); + } } // static -template +template bool LLStringUtilBase::startsWith( - const string_type& string, - const string_type& substr) + const string_type& string, + const string_type& substr) { - if(string.empty() || (substr.empty())) return false; - if (substr.length() > string.length()) return false; - if (0 == string.compare(0, substr.length(), substr)) return true; - return false; + if(string.empty() || (substr.empty())) return false; + if (substr.length() > string.length()) return false; + if (0 == string.compare(0, substr.length(), substr)) return true; + return false; } // static -template +template bool LLStringUtilBase::endsWith( - const string_type& string, - const string_type& substr) -{ - if(string.empty() || (substr.empty())) return false; - size_t sub_len = substr.length(); - size_t str_len = string.length(); - if (sub_len > str_len) return false; - if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; - return false; + const string_type& string, + const string_type& substr) +{ + if(string.empty() || (substr.empty())) return false; + size_t sub_len = substr.length(); + size_t str_len = string.length(); + if (sub_len > str_len) return false; + if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; + return false; } // static @@ -1864,187 +1864,187 @@ auto LLStringUtilBase::getenv(const std::string& key, const string_type& dflt } } -template +template BOOL LLStringUtilBase::convertToBOOL(const string_type& string, BOOL& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - if( - (temp == "1") || - (temp == "T") || - (temp == "t") || - (temp == "TRUE") || - (temp == "true") || - (temp == "True") ) - { - value = TRUE; - return TRUE; - } - else - if( - (temp == "0") || - (temp == "F") || - (temp == "f") || - (temp == "FALSE") || - (temp == "false") || - (temp == "False") ) - { - value = FALSE; - return TRUE; - } - - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + if( + (temp == "1") || + (temp == "T") || + (temp == "t") || + (temp == "TRUE") || + (temp == "true") || + (temp == "True") ) + { + value = TRUE; + return TRUE; + } + else + if( + (temp == "0") || + (temp == "F") || + (temp == "f") || + (temp == "FALSE") || + (temp == "false") || + (temp == "False") ) + { + value = FALSE; + return TRUE; + } + + return FALSE; } -template -BOOL LLStringUtilBase::convertToU8(const string_type& string, U8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) - { - value = (U8) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToU8(const string_type& string, U8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) + { + value = (U8) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToS8(const string_type& string, S8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) - { - value = (S8) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToS8(const string_type& string, S8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) + { + value = (S8) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToS16(const string_type& string, S16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) - { - value = (S16) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToS16(const string_type& string, S16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) + { + value = (S16) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToU16(const string_type& string, U16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) - { - value = (U16) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToU16(const string_type& string, U16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) + { + value = (U16) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToU32(const string_type& string, U32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - U32 v; - std::basic_istringstream i_stream((string_type)temp); - if(i_stream >> v) - { - value = v; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToU32(const string_type& string, U32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + U32 v; + std::basic_istringstream i_stream((string_type)temp); + if(i_stream >> v) + { + value = v; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToS32(const string_type& string, S32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - S32 v; - std::basic_istringstream i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if((LONG_MAX == v) || (LONG_MIN == v)) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToS32(const string_type& string, S32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + S32 v; + std::basic_istringstream i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if((LONG_MAX == v) || (LONG_MIN == v)) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToF32(const string_type& string, F32& value) -{ - F64 value64 = 0.0; - BOOL success = convertToF64(string, value64); - if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) - { - value = (F32) value64; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToF32(const string_type& string, F32& value) +{ + F64 value64 = 0.0; + BOOL success = convertToF64(string, value64); + if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) + { + value = (F32) value64; + return TRUE; + } + return FALSE; } -template +template BOOL LLStringUtilBase::convertToF64(const string_type& string, F64& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - F64 v; - std::basic_istringstream i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + F64 v; + std::basic_istringstream i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template +template void LLStringUtilBase::truncate(string_type& string, size_type count) { - size_type cur_size = string.size(); - string.resize(count < cur_size ? count : cur_size); + size_type cur_size = string.size(); + string.resize(count < cur_size ? count : cur_size); } // The good thing about *declaration* macros, vs. usage macros, is that now diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 63d5bdbb70..d597e90ba0 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -47,7 +47,7 @@ enum LogFieldIndex MSG_FIELD }; -static const char* FieldName[] = +static const char* FieldName[] = { "TIME", "LEVEL", @@ -62,15 +62,15 @@ namespace #ifdef __clang__ # pragma clang diagnostic ignored "-Wunused-function" #endif - void test_that_error_h_includes_enough_things_to_compile_a_message() - { - LL_INFOS() << "!" << LL_ENDL; - } + void test_that_error_h_includes_enough_things_to_compile_a_message() + { + LL_INFOS() << "!" << LL_ENDL; + } } namespace { - static bool fatalWasCalled = false; + static bool fatalWasCalled = false; struct FatalWasCalled: public std::runtime_error { FatalWasCalled(const std::string& what): std::runtime_error(what) {} @@ -96,465 +96,465 @@ namespace namespace tut { - class TestRecorder : public LLError::Recorder - { - public: - TestRecorder() - { - showTime(false); - } - virtual ~TestRecorder() - {} - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) - { - mMessages.push_back(message); - } - - int countMessages() const { return (int) mMessages.size(); } - void clearMessages() { mMessages.clear(); } - - std::string message(int n) const - { - std::ostringstream test_name; - test_name << "testing message " << n << ", not enough messages"; - - tut::ensure(test_name.str(), n < countMessages()); - return mMessages[n]; - } - - void reportMessages() const - { - std::cerr << '\n'; - int n = 0; - for (const auto& msg : mMessages) - { - std::cerr << std::setw(2) << n++ << ": " << msg.substr(0, 100) << '\n'; - } - } - - private: - typedef std::vector MessageVector; - MessageVector mMessages; - }; - - struct ErrorTestData - { - LLError::RecorderPtr mRecorder; - LLError::SettingsStoragePtr mPriorErrorSettings; - - auto recorder() { return std::dynamic_pointer_cast(mRecorder); } - - ErrorTestData(): - mRecorder(new TestRecorder()) - { - fatalWasCalled = false; - - mPriorErrorSettings = LLError::saveAndResetSettings(); - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setFatalFunction(fatalCall); - LLError::addRecorder(mRecorder); - } - - ~ErrorTestData() - { - LLError::removeRecorder(mRecorder); - LLError::restoreSettings(mPriorErrorSettings); - } - - int countMessages() - { - return recorder()->countMessages(); - } - - void clearMessages() - { - recorder()->clearMessages(); - } - - void setWantsTime(bool t) - { - recorder()->showTime(t); - } - - void setWantsMultiline(bool t) - { - recorder()->showMultiline(t); - } - - std::string message(int n) - { - return recorder()->message(n); - } - - void reportMessages() - { - recorder()->reportMessages(); - } - - void ensure_message_count(int expectedCount) - { - ensure_equals("message count", countMessages(), expectedCount); - } - - std::string message_field(int msgnum, LogFieldIndex fieldnum) - { - std::ostringstream test_name; - test_name << "testing message " << msgnum << ", not enough messages"; - tut::ensure(test_name.str(), msgnum < countMessages()); - - std::string msg(message(msgnum)); - - std::string field_value; - - // find the start of the field; fields are separated by a single space - size_t scan = 0; - int on_field = 0; - while ( scan < msg.length() && on_field < fieldnum ) - { - // fields are delimited by one space - if ( ' ' == msg[scan] ) - { - if ( on_field < FUNCTION_FIELD ) - { - on_field++; - } - // except function, which may have embedded spaces so ends with " : " - else if (( on_field == FUNCTION_FIELD ) - && ( ':' == msg[scan+1] && ' ' == msg[scan+2] ) - ) - { - on_field++; - scan +=2; - } - } - scan++; - } - size_t start_field = scan; - size_t fieldlen = 0; - if ( fieldnum < FUNCTION_FIELD ) - { - fieldlen = msg.find(' ', start_field) - start_field; - } - else if ( fieldnum == FUNCTION_FIELD ) - { - fieldlen = msg.find(" : ", start_field) - start_field; - } - else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end - { - fieldlen = msg.length() - start_field; - } - - return msg.substr(start_field, fieldlen); - } - - void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) - { - std::ostringstream test_name; - test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum).substr(0, 100) << "\"\n "; - - try - { - ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText); - } - catch (const failure&) - { - reportMessages(); - throw; - } - } - - void ensure_message_does_not_contain(int n, const std::string& expectedText) - { - std::ostringstream test_name; - test_name << "testing message " << n; - - try - { - ensure_does_not_contain(test_name.str(), message(n), expectedText); - } - catch (const failure&) - { - reportMessages(); - throw; - } - } - }; - - typedef test_group ErrorTestGroup; - typedef ErrorTestGroup::object ErrorTestObject; - - ErrorTestGroup errorTestGroup("error"); - - template<> template<> - void ErrorTestObject::test<1>() - // basic test of output - { - LL_INFOS() << "test" << LL_ENDL; - LL_INFOS() << "bob" << LL_ENDL; - - ensure_message_field_equals(0, MSG_FIELD, "test"); - ensure_message_field_equals(1, MSG_FIELD, "bob"); - } + class TestRecorder : public LLError::Recorder + { + public: + TestRecorder() + { + showTime(false); + } + virtual ~TestRecorder() + {} + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + mMessages.push_back(message); + } + + int countMessages() const { return (int) mMessages.size(); } + void clearMessages() { mMessages.clear(); } + + std::string message(int n) const + { + std::ostringstream test_name; + test_name << "testing message " << n << ", not enough messages"; + + tut::ensure(test_name.str(), n < countMessages()); + return mMessages[n]; + } + + void reportMessages() const + { + std::cerr << '\n'; + int n = 0; + for (const auto& msg : mMessages) + { + std::cerr << std::setw(2) << n++ << ": " << msg.substr(0, 100) << '\n'; + } + } + + private: + typedef std::vector MessageVector; + MessageVector mMessages; + }; + + struct ErrorTestData + { + LLError::RecorderPtr mRecorder; + LLError::SettingsStoragePtr mPriorErrorSettings; + + auto recorder() { return std::dynamic_pointer_cast(mRecorder); } + + ErrorTestData(): + mRecorder(new TestRecorder()) + { + fatalWasCalled = false; + + mPriorErrorSettings = LLError::saveAndResetSettings(); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setFatalFunction(fatalCall); + LLError::addRecorder(mRecorder); + } + + ~ErrorTestData() + { + LLError::removeRecorder(mRecorder); + LLError::restoreSettings(mPriorErrorSettings); + } + + int countMessages() + { + return recorder()->countMessages(); + } + + void clearMessages() + { + recorder()->clearMessages(); + } + + void setWantsTime(bool t) + { + recorder()->showTime(t); + } + + void setWantsMultiline(bool t) + { + recorder()->showMultiline(t); + } + + std::string message(int n) + { + return recorder()->message(n); + } + + void reportMessages() + { + recorder()->reportMessages(); + } + + void ensure_message_count(int expectedCount) + { + ensure_equals("message count", countMessages(), expectedCount); + } + + std::string message_field(int msgnum, LogFieldIndex fieldnum) + { + std::ostringstream test_name; + test_name << "testing message " << msgnum << ", not enough messages"; + tut::ensure(test_name.str(), msgnum < countMessages()); + + std::string msg(message(msgnum)); + + std::string field_value; + + // find the start of the field; fields are separated by a single space + size_t scan = 0; + int on_field = 0; + while ( scan < msg.length() && on_field < fieldnum ) + { + // fields are delimited by one space + if ( ' ' == msg[scan] ) + { + if ( on_field < FUNCTION_FIELD ) + { + on_field++; + } + // except function, which may have embedded spaces so ends with " : " + else if (( on_field == FUNCTION_FIELD ) + && ( ':' == msg[scan+1] && ' ' == msg[scan+2] ) + ) + { + on_field++; + scan +=2; + } + } + scan++; + } + size_t start_field = scan; + size_t fieldlen = 0; + if ( fieldnum < FUNCTION_FIELD ) + { + fieldlen = msg.find(' ', start_field) - start_field; + } + else if ( fieldnum == FUNCTION_FIELD ) + { + fieldlen = msg.find(" : ", start_field) - start_field; + } + else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end + { + fieldlen = msg.length() - start_field; + } + + return msg.substr(start_field, fieldlen); + } + + void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) + { + std::ostringstream test_name; + test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum).substr(0, 100) << "\"\n "; + + try + { + ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText); + } + catch (const failure&) + { + reportMessages(); + throw; + } + } + + void ensure_message_does_not_contain(int n, const std::string& expectedText) + { + std::ostringstream test_name; + test_name << "testing message " << n; + + try + { + ensure_does_not_contain(test_name.str(), message(n), expectedText); + } + catch (const failure&) + { + reportMessages(); + throw; + } + } + }; + + typedef test_group ErrorTestGroup; + typedef ErrorTestGroup::object ErrorTestObject; + + ErrorTestGroup errorTestGroup("error"); + + template<> template<> + void ErrorTestObject::test<1>() + // basic test of output + { + LL_INFOS() << "test" << LL_ENDL; + LL_INFOS() << "bob" << LL_ENDL; + + ensure_message_field_equals(0, MSG_FIELD, "test"); + ensure_message_field_equals(1, MSG_FIELD, "bob"); + } } namespace { - void writeSome() - { - LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; - LL_INFOS("WriteTag") << "two" << LL_ENDL; - LL_WARNS("WriteTag") << "three" << LL_ENDL; - CATCH(LL_ERRS("WriteTag"), "four"); - } + void writeSome() + { + LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; + LL_INFOS("WriteTag") << "two" << LL_ENDL; + LL_WARNS("WriteTag") << "three" << LL_ENDL; + CATCH(LL_ERRS("WriteTag"), "four"); + } }; namespace tut { - template<> template<> - void ErrorTestObject::test<2>() - // messages are filtered based on default level - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - writeSome(); - ensure_message_field_equals(0, MSG_FIELD, "one"); - ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); - ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#"); - ensure_message_field_equals(1, MSG_FIELD, "two"); - ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); - ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#"); - ensure_message_field_equals(2, MSG_FIELD, "three"); - ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); - ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#"); - ensure_message_field_equals(3, MSG_FIELD, "four"); - ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(5); - - LLError::setDefaultLevel(LLError::LEVEL_INFO); - writeSome(); - ensure_message_field_equals(5, MSG_FIELD, "two"); - ensure_message_field_equals(6, MSG_FIELD, "three"); - ensure_message_field_equals(7, MSG_FIELD, "four"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(9); - - LLError::setDefaultLevel(LLError::LEVEL_WARN); - writeSome(); - ensure_message_field_equals(9, MSG_FIELD, "three"); - ensure_message_field_equals(10, MSG_FIELD, "four"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(12); - - LLError::setDefaultLevel(LLError::LEVEL_ERROR); - writeSome(); - ensure_message_field_equals(12, MSG_FIELD, "four"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(14); - - LLError::setDefaultLevel(LLError::LEVEL_NONE); - writeSome(); - ensure_message_count(14); - } - - template<> template<> - void ErrorTestObject::test<3>() - // error type string in output - { - writeSome(); - ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); - ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); - ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); - ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(5); - } - - template<> template<> - void ErrorTestObject::test<4>() - // file abbreviation - { - std::string prev, abbreviateFile = __FILE__; - do - { - prev = abbreviateFile; - abbreviateFile = LLError::abbreviateFile(abbreviateFile); - // __FILE__ is assumed to end with - // indra/llcommon/tests/llerror_test.cpp. This test used to call - // abbreviateFile() exactly once, then check below whether it - // still contained the string 'indra'. That fails if the FIRST - // part of the pathname also contains indra! Certain developer - // machine images put local directory trees under - // /ngi-persist/indra, which is where we observe the problem. So - // now, keep calling abbreviateFile() until it returns its - // argument unchanged, THEN check. - } while (abbreviateFile != prev); - - ensure_ends_with("file name abbreviation", - abbreviateFile, - "llcommon/tests/llerror_test.cpp" - ); - ensure_does_not_contain("file name abbreviation", - abbreviateFile, "indra"); - - std::string someFile = + template<> template<> + void ErrorTestObject::test<2>() + // messages are filtered based on default level + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + writeSome(); + ensure_message_field_equals(0, MSG_FIELD, "one"); + ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); + ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#"); + ensure_message_field_equals(1, MSG_FIELD, "two"); + ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); + ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#"); + ensure_message_field_equals(2, MSG_FIELD, "three"); + ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); + ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#"); + ensure_message_field_equals(3, MSG_FIELD, "four"); + ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); + ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(5); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + writeSome(); + ensure_message_field_equals(5, MSG_FIELD, "two"); + ensure_message_field_equals(6, MSG_FIELD, "three"); + ensure_message_field_equals(7, MSG_FIELD, "four"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(9); + + LLError::setDefaultLevel(LLError::LEVEL_WARN); + writeSome(); + ensure_message_field_equals(9, MSG_FIELD, "three"); + ensure_message_field_equals(10, MSG_FIELD, "four"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(12); + + LLError::setDefaultLevel(LLError::LEVEL_ERROR); + writeSome(); + ensure_message_field_equals(12, MSG_FIELD, "four"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(14); + + LLError::setDefaultLevel(LLError::LEVEL_NONE); + writeSome(); + ensure_message_count(14); + } + + template<> template<> + void ErrorTestObject::test<3>() + // error type string in output + { + writeSome(); + ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); + ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); + ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); + ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(5); + } + + template<> template<> + void ErrorTestObject::test<4>() + // file abbreviation + { + std::string prev, abbreviateFile = __FILE__; + do + { + prev = abbreviateFile; + abbreviateFile = LLError::abbreviateFile(abbreviateFile); + // __FILE__ is assumed to end with + // indra/llcommon/tests/llerror_test.cpp. This test used to call + // abbreviateFile() exactly once, then check below whether it + // still contained the string 'indra'. That fails if the FIRST + // part of the pathname also contains indra! Certain developer + // machine images put local directory trees under + // /ngi-persist/indra, which is where we observe the problem. So + // now, keep calling abbreviateFile() until it returns its + // argument unchanged, THEN check. + } while (abbreviateFile != prev); + + ensure_ends_with("file name abbreviation", + abbreviateFile, + "llcommon/tests/llerror_test.cpp" + ); + ensure_does_not_contain("file name abbreviation", + abbreviateFile, "indra"); + + std::string someFile = #if LL_WINDOWS - "C:/amy/bob/cam.cpp" + "C:/amy/bob/cam.cpp" #else - "/amy/bob/cam.cpp" + "/amy/bob/cam.cpp" #endif - ; - std::string someAbbreviation = LLError::abbreviateFile(someFile); + ; + std::string someAbbreviation = LLError::abbreviateFile(someFile); - ensure_equals("non-indra file abbreviation", - someAbbreviation, someFile); - } + ensure_equals("non-indra file abbreviation", + someAbbreviation, someFile); + } } namespace { - std::string locationString(int line) - { - std::ostringstream location; - location << LLError::abbreviateFile(__FILE__) - << "(" << line << ")"; - - return location.str(); - } - - std::string writeReturningLocation() - { - LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; - return locationString(this_line); - } - - void writeReturningLocationAndFunction(std::string& location, std::string& function) - { - LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; - location = locationString(this_line); - function = __FUNCTION__; - } - - std::string errorReturningLocation() - { - int this_line = __LINE__; CATCH(LL_ERRS(), "die"); - return locationString(this_line); - } + std::string locationString(int line) + { + std::ostringstream location; + location << LLError::abbreviateFile(__FILE__) + << "(" << line << ")"; + + return location.str(); + } + + std::string writeReturningLocation() + { + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + return locationString(this_line); + } + + void writeReturningLocationAndFunction(std::string& location, std::string& function) + { + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + location = locationString(this_line); + function = __FUNCTION__; + } + + std::string errorReturningLocation() + { + int this_line = __LINE__; CATCH(LL_ERRS(), "die"); + return locationString(this_line); + } } /* The following helper functions and class members all log a simple message - from some particular function scope. Each function takes a bool argument - that indicates if it should log its own name or not (in the manner that - existing log messages often do.) The functions all return their C++ - name so that test can be substantial mechanized. + from some particular function scope. Each function takes a bool argument + that indicates if it should log its own name or not (in the manner that + existing log messages often do.) The functions all return their C++ + name so that test can be substantial mechanized. */ std::string logFromGlobal(bool id) { - LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; - return "logFromGlobal"; + LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; + return "logFromGlobal"; } static std::string logFromStatic(bool id) { - LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; - return "logFromStatic"; + LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; + return "logFromStatic"; } namespace { - std::string logFromAnon(bool id) - { - LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; - return "logFromAnon"; - } + std::string logFromAnon(bool id) + { + LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; + return "logFromAnon"; + } } namespace Foo { - std::string logFromNamespace(bool id) - { - LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; - //return "Foo::logFromNamespace"; - // there is no standard way to get the namespace name, hence - // we won't be testing for it - return "logFromNamespace"; - } + std::string logFromNamespace(bool id) + { + LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; + //return "Foo::logFromNamespace"; + // there is no standard way to get the namespace name, hence + // we won't be testing for it + return "logFromNamespace"; + } } namespace { - class ClassWithNoLogType { - public: - std::string logFromMember(bool id) - { - LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; - return "ClassWithNoLogType::logFromMember"; - } - static std::string logFromStatic(bool id) - { - LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; - return "ClassWithNoLogType::logFromStatic"; - } - }; - - class ClassWithLogType { - LOG_CLASS(ClassWithLogType); - public: - std::string logFromMember(bool id) - { - LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; - return "ClassWithLogType::logFromMember"; - } - static std::string logFromStatic(bool id) - { - LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; - return "ClassWithLogType::logFromStatic"; - } - }; - - std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } - std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } - std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } - - void ensure_has(const std::string& message, - const std::string& actual, const std::string& expected) - { - std::string::size_type n1 = actual.find(expected); - if (n1 == std::string::npos) - { - std::stringstream ss; - ss << message << ": " << "expected to find a copy of '" << expected - << "' in actual '" << actual << "'"; - throw tut::failure(ss.str().c_str()); - } - } - - typedef std::string (*LogFromFunction)(bool); - void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, - const std::string& class_name = "") - { - std::dynamic_pointer_cast(recorder)->clearMessages(); - std::string name = f(false); - f(true); - - std::string messageWithoutName = std::dynamic_pointer_cast(recorder)->message(0); - std::string messageWithName = std::dynamic_pointer_cast(recorder)->message(1); - - ensure_has(name + " logged without name", - messageWithoutName, name); - ensure_has(name + " logged with name", - messageWithName, name); - - if (!class_name.empty()) - { - ensure_has(name + "logged without name", - messageWithoutName, class_name); - ensure_has(name + "logged with name", - messageWithName, class_name); - } - } + class ClassWithNoLogType { + public: + std::string logFromMember(bool id) + { + LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; + return "ClassWithNoLogType::logFromMember"; + } + static std::string logFromStatic(bool id) + { + LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; + return "ClassWithNoLogType::logFromStatic"; + } + }; + + class ClassWithLogType { + LOG_CLASS(ClassWithLogType); + public: + std::string logFromMember(bool id) + { + LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; + return "ClassWithLogType::logFromMember"; + } + static std::string logFromStatic(bool id) + { + LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; + return "ClassWithLogType::logFromStatic"; + } + }; + + std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } + std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } + std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } + + void ensure_has(const std::string& message, + const std::string& actual, const std::string& expected) + { + std::string::size_type n1 = actual.find(expected); + if (n1 == std::string::npos) + { + std::stringstream ss; + ss << message << ": " << "expected to find a copy of '" << expected + << "' in actual '" << actual << "'"; + throw tut::failure(ss.str().c_str()); + } + } + + typedef std::string (*LogFromFunction)(bool); + void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, + const std::string& class_name = "") + { + std::dynamic_pointer_cast(recorder)->clearMessages(); + std::string name = f(false); + f(true); + + std::string messageWithoutName = std::dynamic_pointer_cast(recorder)->message(0); + std::string messageWithName = std::dynamic_pointer_cast(recorder)->message(1); + + ensure_has(name + " logged without name", + messageWithoutName, name); + ensure_has(name + " logged with name", + messageWithName, name); + + if (!class_name.empty()) + { + ensure_has(name + "logged without name", + messageWithoutName, class_name); + ensure_has(name + "logged with name", + messageWithName, class_name); + } + } } namespace @@ -578,7 +578,7 @@ namespace tut // backslash, return, and newline are not escaped with backslashes { LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - setWantsMultiline(true); + setWantsMultiline(true); writeMsgNeedsEscaping(); // but should not be now ensure_message_field_equals(0, MSG_FIELD, "backslash\\"); ensure_message_field_equals(1, MSG_FIELD, "newline\nafternewline"); @@ -592,329 +592,329 @@ namespace tut namespace tut { - template<> template<> - // class/function information in output - void ErrorTestObject::test<6>() - { - testLogName(mRecorder, logFromGlobal); - testLogName(mRecorder, logFromStatic); - testLogName(mRecorder, logFromAnon); - testLogName(mRecorder, logFromNamespace); - testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); - testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); - } + template<> template<> + // class/function information in output + void ErrorTestObject::test<6>() + { + testLogName(mRecorder, logFromGlobal); + testLogName(mRecorder, logFromStatic); + testLogName(mRecorder, logFromAnon); + testLogName(mRecorder, logFromNamespace); + testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); + testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); + } } namespace { - std::string innerLogger() - { - LL_INFOS() << "inside" << LL_ENDL; - return "moo"; - } - - std::string outerLogger() - { - LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; - return "bar"; - } - - class LogWhileLogging - { - public: - void print(std::ostream& out) const - { - LL_INFOS() << "logging" << LL_ENDL; - out << "baz"; - } - }; - - std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) - { l.print(out); return out; } - - void metaLogger() - { - LogWhileLogging l; - LL_INFOS() << "meta(" << l << ")" << LL_ENDL; - } + std::string innerLogger() + { + LL_INFOS() << "inside" << LL_ENDL; + return "moo"; + } + + std::string outerLogger() + { + LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; + return "bar"; + } + + class LogWhileLogging + { + public: + void print(std::ostream& out) const + { + LL_INFOS() << "logging" << LL_ENDL; + out << "baz"; + } + }; + + std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) + { l.print(out); return out; } + + void metaLogger() + { + LogWhileLogging l; + LL_INFOS() << "meta(" << l << ")" << LL_ENDL; + } } namespace tut { - template<> template<> - // handle nested logging - void ErrorTestObject::test<7>() - { - outerLogger(); - ensure_message_field_equals(0, MSG_FIELD, "inside"); - ensure_message_field_equals(1, MSG_FIELD, "outside(moo)"); - ensure_message_count(2); - - metaLogger(); - ensure_message_field_equals(2, MSG_FIELD, "logging"); - ensure_message_field_equals(3, MSG_FIELD, "meta(baz)"); - ensure_message_count(4); - } - - template<> template<> - // special handling of LL_ERRS() calls - void ErrorTestObject::test<8>() - { - std::string location = errorReturningLocation(); - - ensure_message_field_equals(0, LOCATION_FIELD, location); - ensure_message_field_equals(0, MSG_FIELD, "die"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(2); - - ensure("fatal callback called", fatalWasCalled); - } + template<> template<> + // handle nested logging + void ErrorTestObject::test<7>() + { + outerLogger(); + ensure_message_field_equals(0, MSG_FIELD, "inside"); + ensure_message_field_equals(1, MSG_FIELD, "outside(moo)"); + ensure_message_count(2); + + metaLogger(); + ensure_message_field_equals(2, MSG_FIELD, "logging"); + ensure_message_field_equals(3, MSG_FIELD, "meta(baz)"); + ensure_message_count(4); + } + + template<> template<> + // special handling of LL_ERRS() calls + void ErrorTestObject::test<8>() + { + std::string location = errorReturningLocation(); + + ensure_message_field_equals(0, LOCATION_FIELD, location); + ensure_message_field_equals(0, MSG_FIELD, "die"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(2); + + ensure("fatal callback called", fatalWasCalled); + } } namespace { - std::string roswell() - { - return "1947-07-08T03:04:05Z"; - } - - void ufoSighting() - { - LL_INFOS() << "ufo" << LL_ENDL; - } + std::string roswell() + { + return "1947-07-08T03:04:05Z"; + } + + void ufoSighting() + { + LL_INFOS() << "ufo" << LL_ENDL; + } } namespace tut { - template<> template<> - // time in output (for recorders that need it) - void ErrorTestObject::test<9>() - { - LLError::setTimeFunction(roswell); - - setWantsTime(false); - ufoSighting(); - ensure_message_field_equals(0, MSG_FIELD, "ufo"); - ensure_message_does_not_contain(0, roswell()); - - setWantsTime(true); - ufoSighting(); - ensure_message_field_equals(1, MSG_FIELD, "ufo"); - ensure_message_field_equals(1, TIME_FIELD, roswell()); - } - - template<> template<> - // output order - void ErrorTestObject::test<10>() - { - LLError::setTimeFunction(roswell); - setWantsTime(true); - - std::string location, - function; - writeReturningLocationAndFunction(location, function); - - ensure_equals("order is time level tags location function message", + template<> template<> + // time in output (for recorders that need it) + void ErrorTestObject::test<9>() + { + LLError::setTimeFunction(roswell); + + setWantsTime(false); + ufoSighting(); + ensure_message_field_equals(0, MSG_FIELD, "ufo"); + ensure_message_does_not_contain(0, roswell()); + + setWantsTime(true); + ufoSighting(); + ensure_message_field_equals(1, MSG_FIELD, "ufo"); + ensure_message_field_equals(1, TIME_FIELD, roswell()); + } + + template<> template<> + // output order + void ErrorTestObject::test<10>() + { + LLError::setTimeFunction(roswell); + setWantsTime(true); + + std::string location, + function; + writeReturningLocationAndFunction(location, function); + + ensure_equals("order is time level tags location function message", message(0), roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple"); - } + } - template<> template<> - // multiple recorders - void ErrorTestObject::test<11>() - { - LLError::RecorderPtr altRecorder(new TestRecorder()); - LLError::addRecorder(altRecorder); + template<> template<> + // multiple recorders + void ErrorTestObject::test<11>() + { + LLError::RecorderPtr altRecorder(new TestRecorder()); + LLError::addRecorder(altRecorder); - LL_INFOS() << "boo" << LL_ENDL; + LL_INFOS() << "boo" << LL_ENDL; - ensure_message_field_equals(0, MSG_FIELD, "boo"); - ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 1); - ensure_contains("alt recorder message 0", std::dynamic_pointer_cast(altRecorder)->message(0), "boo"); + ensure_message_field_equals(0, MSG_FIELD, "boo"); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 1); + ensure_contains("alt recorder message 0", std::dynamic_pointer_cast(altRecorder)->message(0), "boo"); - LLError::setTimeFunction(roswell); + LLError::setTimeFunction(roswell); - LLError::RecorderPtr anotherRecorder(new TestRecorder()); - std::dynamic_pointer_cast(anotherRecorder)->showTime(true); - LLError::addRecorder(anotherRecorder); + LLError::RecorderPtr anotherRecorder(new TestRecorder()); + std::dynamic_pointer_cast(anotherRecorder)->showTime(true); + LLError::addRecorder(anotherRecorder); - LL_INFOS() << "baz" << LL_ENDL; + LL_INFOS() << "baz" << LL_ENDL; - std::string when = roswell(); + std::string when = roswell(); - ensure_message_does_not_contain(1, when); - ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 2); - ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast(altRecorder)->message(1), when); - ensure_equals("another recorder count", std::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); - ensure_contains("another recorder message 0", std::dynamic_pointer_cast(anotherRecorder)->message(0), when); + ensure_message_does_not_contain(1, when); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 2); + ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast(altRecorder)->message(1), when); + ensure_equals("another recorder count", std::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); + ensure_contains("another recorder message 0", std::dynamic_pointer_cast(anotherRecorder)->message(0), when); - LLError::removeRecorder(altRecorder); - LLError::removeRecorder(anotherRecorder); - } + LLError::removeRecorder(altRecorder); + LLError::removeRecorder(anotherRecorder); + } } class TestAlpha { - LOG_CLASS(TestAlpha); + LOG_CLASS(TestAlpha); public: - static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } - static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } - static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } - static void doError() { CATCH(LL_ERRS(), "ate eels"); } - static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } + static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "ate eels"); } + static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; class TestBeta { - LOG_CLASS(TestBeta); + LOG_CLASS(TestBeta); public: - static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } - static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } - static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } - static void doError() { CATCH(LL_ERRS(), "big easy"); } - static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } + static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "big easy"); } + static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; namespace tut { - template<> template<> - // filtering by class - void ErrorTestObject::test<12>() - { - LLError::setDefaultLevel(LLError::LEVEL_WARN); - LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); - - TestAlpha::doAll(); - TestBeta::doAll(); - - ensure_message_field_equals(0, MSG_FIELD, "aim west"); - ensure_message_field_equals(1, MSG_FIELD, "ate eels"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_field_equals(3, MSG_FIELD, "buy iron"); - ensure_message_field_equals(4, MSG_FIELD, "bad word"); - ensure_message_field_equals(5, MSG_FIELD, "big easy"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(7); - } - - template<> template<> - // filtering by function, and that it will override class filtering - void ErrorTestObject::test<13>() - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); - LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); - LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); - - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "buy iron"); - ensure_message_field_equals(1, MSG_FIELD, "bad word"); - ensure_message_count(2); - } - - template<> template<> - // filtering by file - // and that it is overridden by both class and function filtering - void ErrorTestObject::test<14>() - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setFileLevel(LLError::abbreviateFile(__FILE__), - LLError::LEVEL_WARN); - LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); - LLError::setFunctionLevel("TestAlpha::doError", - LLError::LEVEL_NONE); - LLError::setFunctionLevel("TestBeta::doError", - LLError::LEVEL_NONE); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "any idea"); - ensure_message_field_equals(1, MSG_FIELD, "aim west"); - ensure_message_field_equals(2, MSG_FIELD, "bad word"); - ensure_message_count(3); - } - - template<> template<> - // proper cached, efficient lookup of filtering - void ErrorTestObject::test<15>() - { - LLError::setDefaultLevel(LLError::LEVEL_NONE); - - TestAlpha::doInfo(); - ensure_message_count(0); - ensure_equals("first check", LLError::shouldLogCallCount(), 1); - TestAlpha::doInfo(); - ensure_message_count(0); - ensure_equals("second check", LLError::shouldLogCallCount(), 1); - - LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); - TestAlpha::doInfo(); - ensure_message_count(1); - ensure_equals("third check", LLError::shouldLogCallCount(), 2); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); - - LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); - } - - template<> template<> - // configuration from LLSD - void ErrorTestObject::test<16>() - { - LLSD config; - config["print-location"] = true; - config["default-level"] = "DEBUG"; - - LLSD set1; - set1["level"] = "WARN"; + template<> template<> + // filtering by class + void ErrorTestObject::test<12>() + { + LLError::setDefaultLevel(LLError::LEVEL_WARN); + LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); + + TestAlpha::doAll(); + TestBeta::doAll(); + + ensure_message_field_equals(0, MSG_FIELD, "aim west"); + ensure_message_field_equals(1, MSG_FIELD, "ate eels"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_field_equals(3, MSG_FIELD, "buy iron"); + ensure_message_field_equals(4, MSG_FIELD, "bad word"); + ensure_message_field_equals(5, MSG_FIELD, "big easy"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(7); + } + + template<> template<> + // filtering by function, and that it will override class filtering + void ErrorTestObject::test<13>() + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); + LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); + LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); + + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "buy iron"); + ensure_message_field_equals(1, MSG_FIELD, "bad word"); + ensure_message_count(2); + } + + template<> template<> + // filtering by file + // and that it is overridden by both class and function filtering + void ErrorTestObject::test<14>() + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setFileLevel(LLError::abbreviateFile(__FILE__), + LLError::LEVEL_WARN); + LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); + LLError::setFunctionLevel("TestAlpha::doError", + LLError::LEVEL_NONE); + LLError::setFunctionLevel("TestBeta::doError", + LLError::LEVEL_NONE); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "any idea"); + ensure_message_field_equals(1, MSG_FIELD, "aim west"); + ensure_message_field_equals(2, MSG_FIELD, "bad word"); + ensure_message_count(3); + } + + template<> template<> + // proper cached, efficient lookup of filtering + void ErrorTestObject::test<15>() + { + LLError::setDefaultLevel(LLError::LEVEL_NONE); + + TestAlpha::doInfo(); + ensure_message_count(0); + ensure_equals("first check", LLError::shouldLogCallCount(), 1); + TestAlpha::doInfo(); + ensure_message_count(0); + ensure_equals("second check", LLError::shouldLogCallCount(), 1); + + LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); + TestAlpha::doInfo(); + ensure_message_count(1); + ensure_equals("third check", LLError::shouldLogCallCount(), 2); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); + + LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); + } + + template<> template<> + // configuration from LLSD + void ErrorTestObject::test<16>() + { + LLSD config; + config["print-location"] = true; + config["default-level"] = "DEBUG"; + + LLSD set1; + set1["level"] = "WARN"; set1["files"][0] = LLError::abbreviateFile(__FILE__); - LLSD set2; - set2["level"] = "INFO"; - set2["classes"][0] = "TestAlpha"; - - LLSD set3; - set3["level"] = "NONE"; - set3["functions"][0] = "TestAlpha::doError"; - set3["functions"][1] = "TestBeta::doError"; - - config["settings"][0] = set1; - config["settings"][1] = set2; - config["settings"][2] = set3; - - LLError::configure(config); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "any idea"); - ensure_message_field_equals(1, MSG_FIELD, "aim west"); - ensure_message_field_equals(2, MSG_FIELD, "bad word"); - ensure_message_count(3); - - // make sure reconfiguring works - LLSD config2; - config2["default-level"] = "WARN"; - - LLError::configure(config2); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(3, MSG_FIELD, "aim west"); - ensure_message_field_equals(4, MSG_FIELD, "ate eels"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_field_equals(6, MSG_FIELD, "bad word"); - ensure_message_field_equals(7, MSG_FIELD, "big easy"); - // LL_ERRS() produces 2 recordMessage() calls - ensure_message_count(9); - } + LLSD set2; + set2["level"] = "INFO"; + set2["classes"][0] = "TestAlpha"; + + LLSD set3; + set3["level"] = "NONE"; + set3["functions"][0] = "TestAlpha::doError"; + set3["functions"][1] = "TestBeta::doError"; + + config["settings"][0] = set1; + config["settings"][1] = set2; + config["settings"][2] = set3; + + LLError::configure(config); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "any idea"); + ensure_message_field_equals(1, MSG_FIELD, "aim west"); + ensure_message_field_equals(2, MSG_FIELD, "bad word"); + ensure_message_count(3); + + // make sure reconfiguring works + LLSD config2; + config2["default-level"] = "WARN"; + + LLError::configure(config2); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(3, MSG_FIELD, "aim west"); + ensure_message_field_equals(4, MSG_FIELD, "ate eels"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_field_equals(6, MSG_FIELD, "bad word"); + ensure_message_field_equals(7, MSG_FIELD, "big easy"); + // LL_ERRS() produces 2 recordMessage() calls + ensure_message_count(9); + } } namespace tut @@ -962,16 +962,16 @@ namespace tut } /* Tests left: - handling of classes without LOG_CLASS + handling of classes without LOG_CLASS - live update of filtering from file + live update of filtering from file - syslog recorder - file recorder - cerr/stderr recorder - fixed buffer recorder - windows recorder + syslog recorder + file recorder + cerr/stderr recorder + fixed buffer recorder + windows recorder - mutex use when logging (?) - strange careful about to crash handling (?) + mutex use when logging (?) + strange careful about to crash handling (?) */ diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index bff647cbe8..01c4dd96ac 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize_test.cpp * @date 2006-04 * @brief LLSDSerialize unit tests @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -62,313 +62,313 @@ typedef std::function P std::vector string_to_vector(const std::string& str) { - return std::vector(str.begin(), str.end()); + return std::vector(str.begin(), str.end()); } namespace tut { - struct sd_xml_data - { - sd_xml_data() - { - mFormatter = new LLSDXMLFormatter; - } - LLSD mSD; - LLPointer mFormatter; - void xml_test(const char* name, const std::string& expected) - { - std::ostringstream ostr; - mFormatter->format(mSD, ostr); - ensure_equals(name, ostr.str(), expected); - } - }; - - typedef test_group sd_xml_test; - typedef sd_xml_test::object sd_xml_object; - tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); - - template<> template<> - void sd_xml_object::test<1>() - { - // random atomic tests - std::string expected; - - expected = "\n"; - xml_test("undef", expected); - - mSD = 3463; - expected = "3463\n"; - xml_test("integer", expected); - - mSD = ""; - expected = "\n"; - xml_test("empty string", expected); - - mSD = "foobar"; - expected = "foobar\n"; - xml_test("string", expected); - - mSD = LLUUID::null; - expected = "\n"; - xml_test("null uuid", expected); - - mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); - expected = "c96f9b1e-f589-4100-9774-d98643ce0bed\n"; - xml_test("uuid", expected); - - mSD = LLURI("https://secondlife.com/login"); - expected = "https://secondlife.com/login\n"; - xml_test("uri", expected); - - mSD = LLDate("2006-04-24T16:11:33Z"); - expected = "2006-04-24T16:11:33Z\n"; - xml_test("date", expected); - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - std::vector hello; - hello.push_back('h'); - hello.push_back('e'); - hello.push_back('l'); - hello.push_back('l'); - hello.push_back('o'); - mSD = hello; - expected = "aGVsbG8=\n"; - xml_test("binary", expected); - } - - template<> template<> - void sd_xml_object::test<2>() - { - // tests with boolean values. - std::string expected; - - mFormatter->boolalpha(true); - mSD = true; - expected = "true\n"; - xml_test("bool alpha true", expected); - mSD = false; - expected = "false\n"; - xml_test("bool alpha false", expected); - - mFormatter->boolalpha(false); - mSD = true; - expected = "1\n"; - xml_test("bool true", expected); - mSD = false; - expected = "0\n"; - xml_test("bool false", expected); - } - - - template<> template<> - void sd_xml_object::test<3>() - { - // tests with real values. - std::string expected; - - mFormatter->realFormat("%.2f"); - mSD = 1.0; - expected = "1.00\n"; - xml_test("real 1", expected); - - mSD = -34379.0438; - expected = "-34379.04\n"; - xml_test("real reduced precision", expected); - mFormatter->realFormat("%.4f"); - expected = "-34379.0438\n"; - xml_test("higher precision", expected); - - mFormatter->realFormat("%.0f"); - mSD = 0.0; - expected = "0\n"; - xml_test("no decimal 0", expected); - mSD = 3287.4387; - expected = "3287\n"; - xml_test("no decimal real number", expected); - } - - template<> template<> - void sd_xml_object::test<4>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyArray(); - expected = "\n"; - xml_test("empty array", expected); - - mSD.append(LLSD()); - expected = "\n"; - xml_test("1 element array", expected); - - mSD.append(1); - expected = "1\n"; - xml_test("2 element array", expected); - } - - template<> template<> - void sd_xml_object::test<5>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyMap(); - expected = "\n"; - xml_test("empty map", expected); - - mSD["foo"] = "bar"; - expected = "foobar\n"; - xml_test("1 element map", expected); - - mSD["baz"] = LLSD(); - expected = "bazfoobar\n"; - xml_test("2 element map", expected); - } - - template<> template<> - void sd_xml_object::test<6>() - { - // tests with binary - std::string expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - mSD = string_to_vector("hello"); - expected = "aGVsbG8=\n"; - xml_test("binary", expected); - - mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - expected = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; - xml_test("binary", expected); - } - - class TestLLSDSerializeData - { - public: - TestLLSDSerializeData(); - ~TestLLSDSerializeData(); - - void doRoundTripTests(const std::string&); - void checkRoundTrip(const std::string&, const LLSD& v); - - void setFormatterParser(LLPointer formatter, LLPointer parser) - { - mFormatter = [formatter](const LLSD& data, std::ostream& str) - { - formatter->format(data, str); - }; - // this lambda must be mutable since otherwise the bound 'parser' - // is assumed to point to a const LLSDParser - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable - { - // reset() call is needed since test code re-uses parser object - parser->reset(); - return (parser->parse(istr, data, max_bytes) > 0); - }; - } - - void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) - { - // why does LLSDSerialize::deserialize() reverse the parse() params?? - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) - { - return parser(data, istr, max_bytes); - }; - } - - FormatterFunction mFormatter; - ParserFunction mParser; - }; - - TestLLSDSerializeData::TestLLSDSerializeData() - { - } - - TestLLSDSerializeData::~TestLLSDSerializeData() - { - } - - void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) - { - std::stringstream stream; - mFormatter(v, stream); - //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; - LLSD w; - mParser(stream, w, stream.str().size()); - - try - { - ensure_equals(msg, w, v); - } - catch (...) - { - std::cerr << "the serialized string was:" << std::endl; - std::cerr << stream.str() << std::endl; - throw; - } - } - - static void fillmap(LLSD& root, U32 width, U32 depth) - { - if(depth == 0) - { - root["foo"] = "bar"; - return; - } - - for(U32 i = 0; i < width; ++i) - { - std::string key = llformat("child %d", i); - root[key] = LLSD::emptyMap(); - fillmap(root[key], width, depth - 1); - } - } - - void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) - { - LLSD v; - checkRoundTrip(msg + " undefined", v); - - v = true; - checkRoundTrip(msg + " true bool", v); - - v = false; - checkRoundTrip(msg + " false bool", v); - - v = 1; - checkRoundTrip(msg + " positive int", v); - - v = 0; - checkRoundTrip(msg + " zero int", v); - - v = -1; - checkRoundTrip(msg + " negative int", v); - - v = 1234.5f; - checkRoundTrip(msg + " positive float", v); - - v = 0.0f; - checkRoundTrip(msg + " zero float", v); - - v = -1234.5f; - checkRoundTrip(msg + " negative float", v); - - // FIXME: need a NaN test - - v = LLUUID::null; - checkRoundTrip(msg + " null uuid", v); - - LLUUID newUUID; - newUUID.generate(); - v = newUUID; - checkRoundTrip(msg + " new uuid", v); - - v = ""; - checkRoundTrip(msg + " empty string", v); - - v = "some string"; - checkRoundTrip(msg + " non-empty string", v); - - v = + struct sd_xml_data + { + sd_xml_data() + { + mFormatter = new LLSDXMLFormatter; + } + LLSD mSD; + LLPointer mFormatter; + void xml_test(const char* name, const std::string& expected) + { + std::ostringstream ostr; + mFormatter->format(mSD, ostr); + ensure_equals(name, ostr.str(), expected); + } + }; + + typedef test_group sd_xml_test; + typedef sd_xml_test::object sd_xml_object; + tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); + + template<> template<> + void sd_xml_object::test<1>() + { + // random atomic tests + std::string expected; + + expected = "\n"; + xml_test("undef", expected); + + mSD = 3463; + expected = "3463\n"; + xml_test("integer", expected); + + mSD = ""; + expected = "\n"; + xml_test("empty string", expected); + + mSD = "foobar"; + expected = "foobar\n"; + xml_test("string", expected); + + mSD = LLUUID::null; + expected = "\n"; + xml_test("null uuid", expected); + + mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); + expected = "c96f9b1e-f589-4100-9774-d98643ce0bed\n"; + xml_test("uuid", expected); + + mSD = LLURI("https://secondlife.com/login"); + expected = "https://secondlife.com/login\n"; + xml_test("uri", expected); + + mSD = LLDate("2006-04-24T16:11:33Z"); + expected = "2006-04-24T16:11:33Z\n"; + xml_test("date", expected); + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + std::vector hello; + hello.push_back('h'); + hello.push_back('e'); + hello.push_back('l'); + hello.push_back('l'); + hello.push_back('o'); + mSD = hello; + expected = "aGVsbG8=\n"; + xml_test("binary", expected); + } + + template<> template<> + void sd_xml_object::test<2>() + { + // tests with boolean values. + std::string expected; + + mFormatter->boolalpha(true); + mSD = true; + expected = "true\n"; + xml_test("bool alpha true", expected); + mSD = false; + expected = "false\n"; + xml_test("bool alpha false", expected); + + mFormatter->boolalpha(false); + mSD = true; + expected = "1\n"; + xml_test("bool true", expected); + mSD = false; + expected = "0\n"; + xml_test("bool false", expected); + } + + + template<> template<> + void sd_xml_object::test<3>() + { + // tests with real values. + std::string expected; + + mFormatter->realFormat("%.2f"); + mSD = 1.0; + expected = "1.00\n"; + xml_test("real 1", expected); + + mSD = -34379.0438; + expected = "-34379.04\n"; + xml_test("real reduced precision", expected); + mFormatter->realFormat("%.4f"); + expected = "-34379.0438\n"; + xml_test("higher precision", expected); + + mFormatter->realFormat("%.0f"); + mSD = 0.0; + expected = "0\n"; + xml_test("no decimal 0", expected); + mSD = 3287.4387; + expected = "3287\n"; + xml_test("no decimal real number", expected); + } + + template<> template<> + void sd_xml_object::test<4>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyArray(); + expected = "\n"; + xml_test("empty array", expected); + + mSD.append(LLSD()); + expected = "\n"; + xml_test("1 element array", expected); + + mSD.append(1); + expected = "1\n"; + xml_test("2 element array", expected); + } + + template<> template<> + void sd_xml_object::test<5>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyMap(); + expected = "\n"; + xml_test("empty map", expected); + + mSD["foo"] = "bar"; + expected = "foobar\n"; + xml_test("1 element map", expected); + + mSD["baz"] = LLSD(); + expected = "bazfoobar\n"; + xml_test("2 element map", expected); + } + + template<> template<> + void sd_xml_object::test<6>() + { + // tests with binary + std::string expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + mSD = string_to_vector("hello"); + expected = "aGVsbG8=\n"; + xml_test("binary", expected); + + mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + expected = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; + xml_test("binary", expected); + } + + class TestLLSDSerializeData + { + public: + TestLLSDSerializeData(); + ~TestLLSDSerializeData(); + + void doRoundTripTests(const std::string&); + void checkRoundTrip(const std::string&, const LLSD& v); + + void setFormatterParser(LLPointer formatter, LLPointer parser) + { + mFormatter = [formatter](const LLSD& data, std::ostream& str) + { + formatter->format(data, str); + }; + // this lambda must be mutable since otherwise the bound 'parser' + // is assumed to point to a const LLSDParser + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable + { + // reset() call is needed since test code re-uses parser object + parser->reset(); + return (parser->parse(istr, data, max_bytes) > 0); + }; + } + + void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) + { + // why does LLSDSerialize::deserialize() reverse the parse() params?? + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) + { + return parser(data, istr, max_bytes); + }; + } + + FormatterFunction mFormatter; + ParserFunction mParser; + }; + + TestLLSDSerializeData::TestLLSDSerializeData() + { + } + + TestLLSDSerializeData::~TestLLSDSerializeData() + { + } + + void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) + { + std::stringstream stream; + mFormatter(v, stream); + //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; + LLSD w; + mParser(stream, w, stream.str().size()); + + try + { + ensure_equals(msg, w, v); + } + catch (...) + { + std::cerr << "the serialized string was:" << std::endl; + std::cerr << stream.str() << std::endl; + throw; + } + } + + static void fillmap(LLSD& root, U32 width, U32 depth) + { + if(depth == 0) + { + root["foo"] = "bar"; + return; + } + + for(U32 i = 0; i < width; ++i) + { + std::string key = llformat("child %d", i); + root[key] = LLSD::emptyMap(); + fillmap(root[key], width, depth - 1); + } + } + + void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) + { + LLSD v; + checkRoundTrip(msg + " undefined", v); + + v = true; + checkRoundTrip(msg + " true bool", v); + + v = false; + checkRoundTrip(msg + " false bool", v); + + v = 1; + checkRoundTrip(msg + " positive int", v); + + v = 0; + checkRoundTrip(msg + " zero int", v); + + v = -1; + checkRoundTrip(msg + " negative int", v); + + v = 1234.5f; + checkRoundTrip(msg + " positive float", v); + + v = 0.0f; + checkRoundTrip(msg + " zero float", v); + + v = -1234.5f; + checkRoundTrip(msg + " negative float", v); + + // FIXME: need a NaN test + + v = LLUUID::null; + checkRoundTrip(msg + " null uuid", v); + + LLUUID newUUID; + newUUID.generate(); + v = newUUID; + checkRoundTrip(msg + " new uuid", v); + + v = ""; + checkRoundTrip(msg + " empty string", v); + + v = "some string"; + checkRoundTrip(msg + " non-empty string", v); + + v = "Second Life is a 3-D virtual world entirely built and owned by its residents. " "Since opening to the public in 2003, it has grown explosively and today is " "inhabited by nearly 100,000 people from around the globe.\n" @@ -388,437 +388,437 @@ namespace tut "currency exchanges.\n" "\n" "Welcome to Second Life. We look forward to seeing you in-world!\n" - ; - checkRoundTrip(msg + " long string", v); - - static const U32 block_size = 0x000020; - for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) - { - std::ostringstream out; - - for (U32 c = block; c < block + block_size; ++c) - { - if (c <= 0x000001f - && c != 0x000009 - && c != 0x00000a) - { - // see XML standard, sections 2.2 and 4.1 - continue; - } - if (0x00d800 <= c && c <= 0x00dfff) { continue; } - if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } - if ((c & 0x00fffe) == 0x00fffe) { continue; } - // see Unicode standard, section 15.8 - - if (c <= 0x00007f) - { - out << (char)(c & 0x7f); - } - else if (c <= 0x0007ff) - { - out << (char)(0xc0 | ((c >> 6) & 0x1f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else if (c <= 0x00ffff) - { - out << (char)(0xe0 | ((c >> 12) & 0x0f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else - { - out << (char)(0xf0 | ((c >> 18) & 0x07)); - out << (char)(0x80 | ((c >> 12) & 0x3f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - } - - v = out.str(); - - std::ostringstream blockmsg; - blockmsg << msg << " unicode string block 0x" << std::hex << block; - checkRoundTrip(blockmsg.str(), v); - } - - LLDate epoch; - v = epoch; - checkRoundTrip(msg + " epoch date", v); - - LLDate aDay("2002-12-07T05:07:15.00Z"); - v = aDay; - checkRoundTrip(msg + " date", v); - - LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); - v = path; - checkRoundTrip(msg + " url", v); - - const char source[] = "it must be a blue moon again"; - std::vector data; - // note, includes terminating '\0' - copy(&source[0], &source[sizeof(source)], back_inserter(data)); - - v = data; - checkRoundTrip(msg + " binary", v); - - v = LLSD::emptyMap(); - checkRoundTrip(msg + " empty map", v); - - v = LLSD::emptyMap(); - v["name"] = "luke"; //v.insert("name", "luke"); - v["age"] = 3; //v.insert("age", 3); - checkRoundTrip(msg + " map", v); - - v.clear(); - v["a"]["1"] = true; - v["b"]["0"] = false; - checkRoundTrip(msg + " nested maps", v); - - v = LLSD::emptyArray(); - checkRoundTrip(msg + " empty array", v); - - v = LLSD::emptyArray(); - v.append("ali"); - v.append(28); - checkRoundTrip(msg + " array", v); - - v.clear(); - v[0][0] = true; - v[1][0] = false; - checkRoundTrip(msg + " nested arrays", v); - - v = LLSD::emptyMap(); - fillmap(v, 10, 3); // 10^6 maps - checkRoundTrip(msg + " many nested maps", v); - } - - typedef tut::test_group TestLLSDSerializeGroup; - typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; - TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); - - template<> template<> - void TestLLSDSerializeObject::test<1>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), - new LLSDNotationParser()); - doRoundTripTests("pretty binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<2>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - doRoundTripTests("raw binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<3>() - { - setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); - doRoundTripTests("xml serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<4>() - { - setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); - doRoundTripTests("binary serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<5>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_BINARY)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<6>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_XML)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<7>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); - }; - setParser(LLSDSerialize::deserialize); - // In this test, serialize(LLSD_NOTATION) emits a header recognized by - // deserialize(). - doRoundTripTests("serialize(LLSD_NOTATION)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<8>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDNotationFormatter does not - // emit an llsd/notation header. - doRoundTripTests("LLSDNotationFormatter -> deserialize"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<9>() - { - setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDXMLParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDXMLFormatter does not - // emit an LLSD/XML header. - doRoundTripTests("LLSDXMLFormatter -> deserialize"); - }; + ; + checkRoundTrip(msg + " long string", v); + + static const U32 block_size = 0x000020; + for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) + { + std::ostringstream out; + + for (U32 c = block; c < block + block_size; ++c) + { + if (c <= 0x000001f + && c != 0x000009 + && c != 0x00000a) + { + // see XML standard, sections 2.2 and 4.1 + continue; + } + if (0x00d800 <= c && c <= 0x00dfff) { continue; } + if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } + if ((c & 0x00fffe) == 0x00fffe) { continue; } + // see Unicode standard, section 15.8 + + if (c <= 0x00007f) + { + out << (char)(c & 0x7f); + } + else if (c <= 0x0007ff) + { + out << (char)(0xc0 | ((c >> 6) & 0x1f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else if (c <= 0x00ffff) + { + out << (char)(0xe0 | ((c >> 12) & 0x0f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else + { + out << (char)(0xf0 | ((c >> 18) & 0x07)); + out << (char)(0x80 | ((c >> 12) & 0x3f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + } + + v = out.str(); + + std::ostringstream blockmsg; + blockmsg << msg << " unicode string block 0x" << std::hex << block; + checkRoundTrip(blockmsg.str(), v); + } + + LLDate epoch; + v = epoch; + checkRoundTrip(msg + " epoch date", v); + + LLDate aDay("2002-12-07T05:07:15.00Z"); + v = aDay; + checkRoundTrip(msg + " date", v); + + LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); + v = path; + checkRoundTrip(msg + " url", v); + + const char source[] = "it must be a blue moon again"; + std::vector data; + // note, includes terminating '\0' + copy(&source[0], &source[sizeof(source)], back_inserter(data)); + + v = data; + checkRoundTrip(msg + " binary", v); + + v = LLSD::emptyMap(); + checkRoundTrip(msg + " empty map", v); + + v = LLSD::emptyMap(); + v["name"] = "luke"; //v.insert("name", "luke"); + v["age"] = 3; //v.insert("age", 3); + checkRoundTrip(msg + " map", v); + + v.clear(); + v["a"]["1"] = true; + v["b"]["0"] = false; + checkRoundTrip(msg + " nested maps", v); + + v = LLSD::emptyArray(); + checkRoundTrip(msg + " empty array", v); + + v = LLSD::emptyArray(); + v.append("ali"); + v.append(28); + checkRoundTrip(msg + " array", v); + + v.clear(); + v[0][0] = true; + v[1][0] = false; + checkRoundTrip(msg + " nested arrays", v); + + v = LLSD::emptyMap(); + fillmap(v, 10, 3); // 10^6 maps + checkRoundTrip(msg + " many nested maps", v); + } + + typedef tut::test_group TestLLSDSerializeGroup; + typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; + TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); + + template<> template<> + void TestLLSDSerializeObject::test<1>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), + new LLSDNotationParser()); + doRoundTripTests("pretty binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<2>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + doRoundTripTests("raw binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<3>() + { + setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); + doRoundTripTests("xml serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<4>() + { + setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); + doRoundTripTests("binary serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<5>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_BINARY)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<6>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_XML)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<7>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); + }; + setParser(LLSDSerialize::deserialize); + // In this test, serialize(LLSD_NOTATION) emits a header recognized by + // deserialize(). + doRoundTripTests("serialize(LLSD_NOTATION)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<8>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDNotationFormatter does not + // emit an llsd/notation header. + doRoundTripTests("LLSDNotationFormatter -> deserialize"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<9>() + { + setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDXMLParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDXMLFormatter does not + // emit an LLSD/XML header. + doRoundTripTests("LLSDXMLFormatter -> deserialize"); + }; /*==========================================================================*| - // We do not expect this test to succeed. Without a header, neither - // notation LLSD nor binary LLSD reliably start with a distinct character, - // the way XML LLSD starts with '<'. By convention, we default to notation - // rather than binary. - template<> template<> - void TestLLSDSerializeObject::test<10>() - { - setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDBinaryParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDBinaryFormatter does not - // emit an LLSD/Binary header. - doRoundTripTests("LLSDBinaryFormatter -> deserialize"); - }; + // We do not expect this test to succeed. Without a header, neither + // notation LLSD nor binary LLSD reliably start with a distinct character, + // the way XML LLSD starts with '<'. By convention, we default to notation + // rather than binary. + template<> template<> + void TestLLSDSerializeObject::test<10>() + { + setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDBinaryParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDBinaryFormatter does not + // emit an LLSD/Binary header. + doRoundTripTests("LLSDBinaryFormatter -> deserialize"); + }; |*==========================================================================*/ - /** - * @class TestLLSDParsing - * @brief Base class for of a parse tester. - */ - template - class TestLLSDParsing - { - public: - TestLLSDParsing() - { - mParser = new parser_t; - } - - void ensureParse( - const std::string& msg, - const std::string& in, - const LLSD& expected_value, - S32 expected_count, - S32 depth_limit = -1) - { - std::stringstream input; - input.str(in); - - LLSD parsed_result; - mParser->reset(); // reset() call is needed since test code re-uses mParser - S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); - ensure_equals(msg.c_str(), parsed_result, expected_value); - - // This count check is really only useful for expected - // parse failures, since the ensures equal will already - // require equality. - std::string count_msg(msg); - count_msg += " (count)"; - ensure_equals(count_msg, parsed_count, expected_count); - } - - LLPointer mParser; - }; - - - /** - * @class TestLLSDXMLParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDXMLParsing : public TestLLSDParsing - { - public: - TestLLSDXMLParsing() {} - }; - - typedef tut::test_group TestLLSDXMLParsingGroup; - typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; - TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); - - template<> template<> - void TestLLSDXMLParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed xml", - "ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "not llsd", - "

ha ha

", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "value without llsd", - "ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "key without llsd", - "ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - - template<> template<> - void TestLLSDXMLParsingObject::test<2>() - { - // test handling of unrecognized or unparseable llsd values - LLSD v; - v["amy"] = 23; - v["bob"] = LLSD(); - v["cam"] = 1.23; - - ensureParse( - "unknown data type", - "" - "amy23" - "bob99999999999999999" - "cam1.23" - "", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<3>() - { - // test handling of nested bad data - - LLSD v; - v["amy"] = 23; - v["cam"] = 1.23; - - ensureParse( - "map with html", - "" - "amy23" - "ha ha" - "cam1.23" - "", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["cam"] = 1.23; - ensureParse( - "map with value for key", - "" - "amy23" - "ha ha" - "cam1.23" - "", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["bob"] = LLSD::emptyMap(); - v["cam"] = 1.23; - ensureParse( - "map with map of html", - "" - "amy23" - "bob" - "" - "ha ha" - "" - "cam1.23" - "", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD(); - v[2] = 1.23; - - ensureParse( - "array value of html", - "" - "23" - "ha ha" - "1.23" - "", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD::emptyMap(); - v[2] = 1.23; - ensureParse( - "array with map of html", - "" - "23" - "" - "ha ha" - "" - "1.23" - "", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<4>() - { - // test handling of binary object in XML - std::string xml; - LLSD expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - expected = string_to_vector("hello"); - xml = "aGVsbG8=\n"; - ensureParse( - "the word 'hello' packed in binary encoded base64", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; - xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; - xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; - xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; - xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - } + /** + * @class TestLLSDParsing + * @brief Base class for of a parse tester. + */ + template + class TestLLSDParsing + { + public: + TestLLSDParsing() + { + mParser = new parser_t; + } + + void ensureParse( + const std::string& msg, + const std::string& in, + const LLSD& expected_value, + S32 expected_count, + S32 depth_limit = -1) + { + std::stringstream input; + input.str(in); + + LLSD parsed_result; + mParser->reset(); // reset() call is needed since test code re-uses mParser + S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); + ensure_equals(msg.c_str(), parsed_result, expected_value); + + // This count check is really only useful for expected + // parse failures, since the ensures equal will already + // require equality. + std::string count_msg(msg); + count_msg += " (count)"; + ensure_equals(count_msg, parsed_count, expected_count); + } + + LLPointer mParser; + }; + + + /** + * @class TestLLSDXMLParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDXMLParsing : public TestLLSDParsing + { + public: + TestLLSDXMLParsing() {} + }; + + typedef tut::test_group TestLLSDXMLParsingGroup; + typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; + TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); + + template<> template<> + void TestLLSDXMLParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed xml", + "ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "not llsd", + "

ha ha

", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "value without llsd", + "ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "key without llsd", + "ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + + template<> template<> + void TestLLSDXMLParsingObject::test<2>() + { + // test handling of unrecognized or unparseable llsd values + LLSD v; + v["amy"] = 23; + v["bob"] = LLSD(); + v["cam"] = 1.23; + + ensureParse( + "unknown data type", + "" + "amy23" + "bob99999999999999999" + "cam1.23" + "", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<3>() + { + // test handling of nested bad data + + LLSD v; + v["amy"] = 23; + v["cam"] = 1.23; + + ensureParse( + "map with html", + "" + "amy23" + "ha ha" + "cam1.23" + "", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["cam"] = 1.23; + ensureParse( + "map with value for key", + "" + "amy23" + "ha ha" + "cam1.23" + "", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["bob"] = LLSD::emptyMap(); + v["cam"] = 1.23; + ensureParse( + "map with map of html", + "" + "amy23" + "bob" + "" + "ha ha" + "" + "cam1.23" + "", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD(); + v[2] = 1.23; + + ensureParse( + "array value of html", + "" + "23" + "ha ha" + "1.23" + "", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD::emptyMap(); + v[2] = 1.23; + ensureParse( + "array with map of html", + "" + "23" + "" + "ha ha" + "" + "1.23" + "", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<4>() + { + // test handling of binary object in XML + std::string xml; + LLSD expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + expected = string_to_vector("hello"); + xml = "aGVsbG8=\n"; + ensureParse( + "the word 'hello' packed in binary encoded base64", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; + xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; + xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; + xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; + xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + } template<> template<> void TestLLSDXMLParsingObject::test<5>() @@ -856,272 +856,272 @@ namespace tut } - /* - TODO: - test XML parsing - binary with unrecognized encoding - nested LLSD tags - multiple values inside an LLSD - */ - - - /** - * @class TestLLSDNotationParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDNotationParsing : public TestLLSDParsing - { - public: - TestLLSDNotationParsing() {} - }; - - typedef tut::test_group TestLLSDNotationParsingGroup; - typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; - TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( - "llsd notation parsing"); - - template<> template<> - void TestLLSDNotationParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed notation map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad notation noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<2>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<3>() - { - LLSD val = false; - ensureParse("valid boolean false 0", "false", val, 1); - ensureParse("valid boolean false 1", "f", val, 1); - ensureParse("valid boolean false 2", "0", val, 1); - ensureParse("valid boolean false 3", "F", val, 1); - ensureParse("valid boolean false 4", "FALSE", val, 1); - val = true; - ensureParse("valid boolean true 0", "true", val, 1); - ensureParse("valid boolean true 1", "t", val, 1); - ensureParse("valid boolean true 2", "1", val, 1); - ensureParse("valid boolean true 3", "T", val, 1); - ensureParse("valid boolean true 4", "TRUE", val, 1); - - val.clear(); - ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<4>() - { - LLSD val = 123; - ensureParse("valid integer", "i123", val, 1); - val.clear(); - ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<5>() - { - LLSD val = 456.7; - ensureParse("valid real", "r456.7", val, 1); - val.clear(); - ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<6>() - { - LLUUID id; - LLSD val = id; - ensureParse( - "unparseable uuid", - "u123", - LLSD(), - LLSDParser::PARSE_FAILURE); - id.generate(); - val = id; - std::string uuid_str("u"); - uuid_str += id.asString(); - ensureParse("valid uuid", uuid_str.c_str(), val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<7>() - { - LLSD val = std::string("foolish"); - ensureParse("valid string 1", "\"foolish\"", val, 1); - val = std::string("g'day"); - ensureParse("valid string 2", "\"g'day\"", val, 1); - val = std::string("have a \"nice\" day"); - ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); - val = std::string("whatever"); - ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<8>() - { - ensureParse( - "invalid string 1", - "s(7)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid string 2", - "s(9)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<9>() - { - LLSD val = LLURI("http://www.google.com"); - ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<10>() - { - LLSD val = LLDate("2007-12-28T09:22:53.10Z"); - ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<11>() - { - std::vector vec; - vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); - vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); - LLSD val = vec; - ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); - ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); - ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<12>() - { - ensureParse( - "invalid -- binary length specified too long", - "b(7)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid -- binary length specified way too long", - "b(1000000)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<13>() - { - LLSD val; - val["amy"] = 23; - val["bob"] = LLSD(); - val["cam"] = 1.23; - ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); - - val["bob"] = LLSD::emptyMap(); - val["bob"]["vehicle"] = std::string("bicycle"); - ensureParse( - "nested map", - "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", - val, - 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<14>() - { - LLSD val; - val.append(23); - val.append(LLSD()); - val.append(1.23); - ensureParse("simple array", "[i23,!,r1.23]", val, 4); - val[1] = LLSD::emptyArray(); - val[1].append("bicycle"); - ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<15>() - { - LLSD val; - val["amy"] = 23; - val["bob"]["dogs"] = LLSD::emptyArray(); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][0]["name"] = std::string("groove"); - val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][1]["name"] = std::string("greyley"); - val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); - val["cam"] = 1.23; - ensureParse( - "nested notation", - "{'amy':i23," - " 'bob':{'dogs':[" - "{'name':'groove', 'breed':'samoyed'}," - "{'name':'greyley', 'breed':'chow/husky'}]}," - " 'cam':r1.23}", - val, - 11); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<16>() - { - // text to make sure that incorrect sizes bail because - std::string bad_str("s(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_str, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<17>() - { - // text to make sure that incorrect sizes bail because - std::string bad_bin("b(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_bin, - LLSD(), - LLSDParser::PARSE_FAILURE); - } + /* + TODO: + test XML parsing + binary with unrecognized encoding + nested LLSD tags + multiple values inside an LLSD + */ + + + /** + * @class TestLLSDNotationParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDNotationParsing : public TestLLSDParsing + { + public: + TestLLSDNotationParsing() {} + }; + + typedef tut::test_group TestLLSDNotationParsingGroup; + typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; + TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( + "llsd notation parsing"); + + template<> template<> + void TestLLSDNotationParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed notation map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad notation noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<2>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<3>() + { + LLSD val = false; + ensureParse("valid boolean false 0", "false", val, 1); + ensureParse("valid boolean false 1", "f", val, 1); + ensureParse("valid boolean false 2", "0", val, 1); + ensureParse("valid boolean false 3", "F", val, 1); + ensureParse("valid boolean false 4", "FALSE", val, 1); + val = true; + ensureParse("valid boolean true 0", "true", val, 1); + ensureParse("valid boolean true 1", "t", val, 1); + ensureParse("valid boolean true 2", "1", val, 1); + ensureParse("valid boolean true 3", "T", val, 1); + ensureParse("valid boolean true 4", "TRUE", val, 1); + + val.clear(); + ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<4>() + { + LLSD val = 123; + ensureParse("valid integer", "i123", val, 1); + val.clear(); + ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<5>() + { + LLSD val = 456.7; + ensureParse("valid real", "r456.7", val, 1); + val.clear(); + ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<6>() + { + LLUUID id; + LLSD val = id; + ensureParse( + "unparseable uuid", + "u123", + LLSD(), + LLSDParser::PARSE_FAILURE); + id.generate(); + val = id; + std::string uuid_str("u"); + uuid_str += id.asString(); + ensureParse("valid uuid", uuid_str.c_str(), val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<7>() + { + LLSD val = std::string("foolish"); + ensureParse("valid string 1", "\"foolish\"", val, 1); + val = std::string("g'day"); + ensureParse("valid string 2", "\"g'day\"", val, 1); + val = std::string("have a \"nice\" day"); + ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); + val = std::string("whatever"); + ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<8>() + { + ensureParse( + "invalid string 1", + "s(7)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid string 2", + "s(9)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<9>() + { + LLSD val = LLURI("http://www.google.com"); + ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<10>() + { + LLSD val = LLDate("2007-12-28T09:22:53.10Z"); + ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<11>() + { + std::vector vec; + vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); + vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); + LLSD val = vec; + ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); + ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); + ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<12>() + { + ensureParse( + "invalid -- binary length specified too long", + "b(7)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid -- binary length specified way too long", + "b(1000000)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<13>() + { + LLSD val; + val["amy"] = 23; + val["bob"] = LLSD(); + val["cam"] = 1.23; + ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); + + val["bob"] = LLSD::emptyMap(); + val["bob"]["vehicle"] = std::string("bicycle"); + ensureParse( + "nested map", + "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", + val, + 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<14>() + { + LLSD val; + val.append(23); + val.append(LLSD()); + val.append(1.23); + ensureParse("simple array", "[i23,!,r1.23]", val, 4); + val[1] = LLSD::emptyArray(); + val[1].append("bicycle"); + ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<15>() + { + LLSD val; + val["amy"] = 23; + val["bob"]["dogs"] = LLSD::emptyArray(); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][0]["name"] = std::string("groove"); + val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][1]["name"] = std::string("greyley"); + val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); + val["cam"] = 1.23; + ensureParse( + "nested notation", + "{'amy':i23," + " 'bob':{'dogs':[" + "{'name':'groove', 'breed':'samoyed'}," + "{'name':'greyley', 'breed':'chow/husky'}]}," + " 'cam':r1.23}", + val, + 11); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<16>() + { + // text to make sure that incorrect sizes bail because + std::string bad_str("s(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_str, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<17>() + { + // text to make sure that incorrect sizes bail because + std::string bad_bin("b(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_bin, + LLSD(), + LLSDParser::PARSE_FAILURE); + } template<> template<> void TestLLSDNotationParsingObject::test<18>() { - LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; - LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; + LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; + LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; LLSD deep = LLSD::emptyMap(); deep["level_0"] = level_0; @@ -1166,7 +1166,7 @@ namespace tut template<> template<> void TestLLSDNotationParsingObject::test<20>() { - LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; + LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; LLSD level_49 = LLSD::emptyMap(); level_49["level_49"] = end; LLSD level_48 = LLSD::emptyMap(); level_48["level_48"] = level_49; @@ -1257,536 +1257,536 @@ namespace tut 9); } - /** - * @class TestLLSDBinaryParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDBinaryParsing : public TestLLSDParsing - { - public: - TestLLSDBinaryParsing() {} - }; - - typedef tut::test_group TestLLSDBinaryParsingGroup; - typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; - TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( - "llsd binary parsing"); - - template<> template<> - void TestLLSDBinaryParsingObject::test<1>() - { - std::vector vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - std::string string_expected((char*)&vec[0], vec.size()); - LLSD value = string_expected; - - vec.resize(11); - vec[0] = 's'; // for string - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct string parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<2>() - { - std::vector vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - LLSD value = vec; - - vec.resize(11); - vec[0] = 'b'; // for binary - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct binary parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 1", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 2", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<3>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed binary map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - template<> template<> - void TestLLSDBinaryParsingObject::test<4>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<5>() - { - LLSD val = false; - ensureParse("valid boolean false 2", "0", val, 1); - val = true; - ensureParse("valid boolean true 2", "1", val, 1); - - val.clear(); - ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<6>() - { - std::vector vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('k'); - int key_size_loc = vec.size(); - size = htonl(1); // 1 too short - vec.resize(vec.size() + 4); - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); - vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid key size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing '}') - size = htonl(3); // correct size - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "valid key size, unterminated map", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val["amy"] = 23; - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid map", - str_good, - val, - 2); - - // check w/ incorrect sizes and correct map termination - size = htonl(0); // 1 too few (for the map entry) - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too long", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(2); // 1 too many - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_4((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too short", - str_bad_4, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<7>() - { - std::vector vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); // 1 too short - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); - vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid array size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing ']') - size = htonl(2); // correct size - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "unterminated array", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val.append("amy"); - val.append(23); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid array", - str_good, - val, - 3); - - // check with too many elements - size = htonl(3); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "array too short", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<8>() - { - std::vector vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyMap(); - ensureParse( - "empty map", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<9>() - { - std::vector vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyArray(); - ensureParse( - "empty array", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<10>() - { - std::vector vec; - vec.push_back('l'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(14); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); - vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); - vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); - vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); - vec.push_back('m'); - std::string str_bad((char*)&vec[0], vec.size()); - ensureParse( - "invalid uri length size", - str_bad, - LLSD(), - LLSDParser::PARSE_FAILURE); - - LLSD val; - val = LLURI("http://sl.com"); - size = htonl(13); // correct length - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid key size", - str_good, - val, - 1); - } + /** + * @class TestLLSDBinaryParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDBinaryParsing : public TestLLSDParsing + { + public: + TestLLSDBinaryParsing() {} + }; + + typedef tut::test_group TestLLSDBinaryParsingGroup; + typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; + TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( + "llsd binary parsing"); + + template<> template<> + void TestLLSDBinaryParsingObject::test<1>() + { + std::vector vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + std::string string_expected((char*)&vec[0], vec.size()); + LLSD value = string_expected; + + vec.resize(11); + vec[0] = 's'; // for string + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct string parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<2>() + { + std::vector vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + LLSD value = vec; + + vec.resize(11); + vec[0] = 'b'; // for binary + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct binary parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 1", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 2", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<3>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed binary map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + template<> template<> + void TestLLSDBinaryParsingObject::test<4>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<5>() + { + LLSD val = false; + ensureParse("valid boolean false 2", "0", val, 1); + val = true; + ensureParse("valid boolean true 2", "1", val, 1); + + val.clear(); + ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<6>() + { + std::vector vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('k'); + int key_size_loc = vec.size(); + size = htonl(1); // 1 too short + vec.resize(vec.size() + 4); + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); + vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid key size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing '}') + size = htonl(3); // correct size + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "valid key size, unterminated map", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val["amy"] = 23; + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid map", + str_good, + val, + 2); + + // check w/ incorrect sizes and correct map termination + size = htonl(0); // 1 too few (for the map entry) + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too long", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(2); // 1 too many + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_4((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too short", + str_bad_4, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<7>() + { + std::vector vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); // 1 too short + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); + vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid array size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing ']') + size = htonl(2); // correct size + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "unterminated array", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val.append("amy"); + val.append(23); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid array", + str_good, + val, + 3); + + // check with too many elements + size = htonl(3); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "array too short", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<8>() + { + std::vector vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyMap(); + ensureParse( + "empty map", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<9>() + { + std::vector vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyArray(); + ensureParse( + "empty array", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<10>() + { + std::vector vec; + vec.push_back('l'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(14); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); + vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); + vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); + vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); + vec.push_back('m'); + std::string str_bad((char*)&vec[0], vec.size()); + ensureParse( + "invalid uri length size", + str_bad, + LLSD(), + LLSDParser::PARSE_FAILURE); + + LLSD val; + val = LLURI("http://sl.com"); + size = htonl(13); // correct length + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid key size", + str_good, + val, + 1); + } /* - template<> template<> - void TestLLSDBinaryParsingObject::test<11>() - { - } + template<> template<> + void TestLLSDBinaryParsingObject::test<11>() + { + } */ /** - * @class TestLLSDCrossCompatible - * @brief Miscellaneous serialization and parsing tests - */ - class TestLLSDCrossCompatible - { - public: - TestLLSDCrossCompatible() {} - - void ensureBinaryAndNotation( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation binary count", - count2, - count1); - - // to notation and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndNotation notation count1", - count3, - count2); - LLSD actual_value_notation; - S32 count4 = LLSDSerialize::fromNotation( - actual_value_notation, - str2, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation notation count2", - count4, - count3); - ensure_equals( - (msg + " (binaryandnotation)").c_str(), - actual_value_notation, - input); - } - - void ensureBinaryAndXML( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndXML binary count", - count2, - count1); - - // to xml and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndXML xml count1", - count3, - count2); - LLSD actual_value_xml; - S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); - ensure_equals( - "ensureBinaryAndXML xml count2", - count4, - count3); - ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); - } - }; - - typedef tut::test_group TestLLSDCompatibleGroup; - typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; - TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( - "llsd serialize compatible"); - - template<> template<> - void TestLLSDCompatibleObject::test<1>() - { - LLSD test; - ensureBinaryAndNotation("undef", test); - ensureBinaryAndXML("undef", test); - test = true; - ensureBinaryAndNotation("boolean true", test); - ensureBinaryAndXML("boolean true", test); - test = false; - ensureBinaryAndNotation("boolean false", test); - ensureBinaryAndXML("boolean false", test); - test = 0; - ensureBinaryAndNotation("integer zero", test); - ensureBinaryAndXML("integer zero", test); - test = 1; - ensureBinaryAndNotation("integer positive", test); - ensureBinaryAndXML("integer positive", test); - test = -234567; - ensureBinaryAndNotation("integer negative", test); - ensureBinaryAndXML("integer negative", test); - test = 0.0; - ensureBinaryAndNotation("real zero", test); - ensureBinaryAndXML("real zero", test); - test = 1.0; - ensureBinaryAndNotation("real positive", test); - ensureBinaryAndXML("real positive", test); - test = -1.0; - ensureBinaryAndNotation("real negative", test); - ensureBinaryAndXML("real negative", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<2>() - { - LLSD test; - test = "foobar"; - ensureBinaryAndNotation("string", test); - ensureBinaryAndXML("string", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<3>() - { - LLSD test; - LLUUID id; - id.generate(); - test = id; - ensureBinaryAndNotation("uuid", test); - ensureBinaryAndXML("uuid", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<4>() - { - LLSD test; - test = LLDate(12345.0); - ensureBinaryAndNotation("date", test); - ensureBinaryAndXML("date", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<5>() - { - LLSD test; - test = LLURI("http://www.secondlife.com/"); - ensureBinaryAndNotation("uri", test); - ensureBinaryAndXML("uri", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<6>() - { - LLSD test; - typedef std::vector buf_t; - buf_t val; - for(int ii = 0; ii < 100; ++ii) - { - srand(ii); /* Flawfinder: ignore */ - S32 size = rand() % 100 + 10; - std::generate_n( - std::back_insert_iterator(val), - size, - rand); - } - test = val; - ensureBinaryAndNotation("binary", test); - ensureBinaryAndXML("binary", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<7>() - { - LLSD test; - test = LLSD::emptyArray(); - test.append(1); - test.append("hello"); - ensureBinaryAndNotation("array", test); - ensureBinaryAndXML("array", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<8>() - { - LLSD test; - test = LLSD::emptyArray(); - test["foo"] = "bar"; - test["baz"] = 100; - ensureBinaryAndNotation("map", test); - ensureBinaryAndXML("map", test); - } + * @class TestLLSDCrossCompatible + * @brief Miscellaneous serialization and parsing tests + */ + class TestLLSDCrossCompatible + { + public: + TestLLSDCrossCompatible() {} + + void ensureBinaryAndNotation( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation binary count", + count2, + count1); + + // to notation and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndNotation notation count1", + count3, + count2); + LLSD actual_value_notation; + S32 count4 = LLSDSerialize::fromNotation( + actual_value_notation, + str2, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation notation count2", + count4, + count3); + ensure_equals( + (msg + " (binaryandnotation)").c_str(), + actual_value_notation, + input); + } + + void ensureBinaryAndXML( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndXML binary count", + count2, + count1); + + // to xml and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndXML xml count1", + count3, + count2); + LLSD actual_value_xml; + S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); + ensure_equals( + "ensureBinaryAndXML xml count2", + count4, + count3); + ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); + } + }; + + typedef tut::test_group TestLLSDCompatibleGroup; + typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; + TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( + "llsd serialize compatible"); + + template<> template<> + void TestLLSDCompatibleObject::test<1>() + { + LLSD test; + ensureBinaryAndNotation("undef", test); + ensureBinaryAndXML("undef", test); + test = true; + ensureBinaryAndNotation("boolean true", test); + ensureBinaryAndXML("boolean true", test); + test = false; + ensureBinaryAndNotation("boolean false", test); + ensureBinaryAndXML("boolean false", test); + test = 0; + ensureBinaryAndNotation("integer zero", test); + ensureBinaryAndXML("integer zero", test); + test = 1; + ensureBinaryAndNotation("integer positive", test); + ensureBinaryAndXML("integer positive", test); + test = -234567; + ensureBinaryAndNotation("integer negative", test); + ensureBinaryAndXML("integer negative", test); + test = 0.0; + ensureBinaryAndNotation("real zero", test); + ensureBinaryAndXML("real zero", test); + test = 1.0; + ensureBinaryAndNotation("real positive", test); + ensureBinaryAndXML("real positive", test); + test = -1.0; + ensureBinaryAndNotation("real negative", test); + ensureBinaryAndXML("real negative", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<2>() + { + LLSD test; + test = "foobar"; + ensureBinaryAndNotation("string", test); + ensureBinaryAndXML("string", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<3>() + { + LLSD test; + LLUUID id; + id.generate(); + test = id; + ensureBinaryAndNotation("uuid", test); + ensureBinaryAndXML("uuid", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<4>() + { + LLSD test; + test = LLDate(12345.0); + ensureBinaryAndNotation("date", test); + ensureBinaryAndXML("date", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<5>() + { + LLSD test; + test = LLURI("http://www.secondlife.com/"); + ensureBinaryAndNotation("uri", test); + ensureBinaryAndXML("uri", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<6>() + { + LLSD test; + typedef std::vector buf_t; + buf_t val; + for(int ii = 0; ii < 100; ++ii) + { + srand(ii); /* Flawfinder: ignore */ + S32 size = rand() % 100 + 10; + std::generate_n( + std::back_insert_iterator(val), + size, + rand); + } + test = val; + ensureBinaryAndNotation("binary", test); + ensureBinaryAndXML("binary", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<7>() + { + LLSD test; + test = LLSD::emptyArray(); + test.append(1); + test.append("hello"); + ensureBinaryAndNotation("array", test); + ensureBinaryAndXML("array", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<8>() + { + LLSD test; + test = LLSD::emptyArray(); + test["foo"] = "bar"; + test["baz"] = 100; + ensureBinaryAndNotation("map", test); + ensureBinaryAndXML("map", test); + } // helper for TestPythonCompatible static std::string import_llsd("import os.path\n" @@ -2129,7 +2129,7 @@ namespace tut item.asReal(), 3.14, 7); // 7 bits ~= 0.01 ensure("Failed to read LLSD::String from Python", itemFromStream(inf, item, parse)); - ensure_equals(item.asString(), + ensure_equals(item.asString(), "This string\n" "has several\n" "lines."); diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 750d4e21b9..49d5b4fbdb 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldir.cpp * @brief implementation of directory utilities base class * * $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$ */ @@ -37,7 +37,7 @@ #include "lldir.h" #include "llerror.h" -#include "lltimer.h" // ms_sleep() +#include "lltimer.h" // ms_sleep() #include "lluuid.h" #include "lldiriterator.h" @@ -69,28 +69,28 @@ LLDir *gDirUtilp = (LLDir *)&gDirUtil; /// Values for findSkinnedFilenames(subdir) parameter const char - *LLDir::XUI = "xui", - *LLDir::TEXTURES = "textures", - *LLDir::SKINBASE = ""; + *LLDir::XUI = "xui", + *LLDir::TEXTURES = "textures", + *LLDir::SKINBASE = ""; static const char* const empty = ""; std::string LLDir::sDumpDir = ""; LLDir::LLDir() -: mAppName(""), - mExecutablePathAndName(""), - mExecutableFilename(""), - mExecutableDir(""), - mAppRODataDir(""), - mOSUserDir(""), - mOSUserAppDir(""), - mLindenUserDir(""), - mOSCacheDir(""), - mCAFile(""), - mTempDir(""), - mDirDelimiter("/"), // fallback to forward slash if not overridden - mLanguage("en"), - mUserName("undefined") +: mAppName(""), + mExecutablePathAndName(""), + mExecutableFilename(""), + mExecutableDir(""), + mAppRODataDir(""), + mOSUserDir(""), + mOSUserAppDir(""), + mLindenUserDir(""), + mOSCacheDir(""), + mCAFile(""), + mTempDir(""), + mDirDelimiter("/"), // fallback to forward slash if not overridden + mLanguage("en"), + mUserName("undefined") { } @@ -109,7 +109,7 @@ std::vector LLDir::getFilesInDir(const std::string &dirname) #endif std::vector v; - + if (exists(p)) { if (is_directory(p)) @@ -127,188 +127,188 @@ std::vector LLDir::getFilesInDir(const std::string &dirname) } } return v; -} - +} + S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { - S32 count = 0; - std::string filename; - std::string fullpath; - S32 result; - - // File masks starting with "/" will match nothing, so we consider them invalid. - if (LLStringUtil::startsWith(mask, getDirDelimiter())) - { - LL_WARNS() << "Invalid file mask: " << mask << LL_ENDL; - llassert(!"Invalid file mask"); - } - - LLDirIterator iter(dirname, mask); - while (iter.next(filename)) - { - fullpath = add(dirname, filename); - - if(LLFile::isdir(fullpath)) - { - // skipping directory traversal filenames - count++; - continue; - } - - S32 retry_count = 0; - while (retry_count < 5) - { - if (0 != LLFile::remove(fullpath)) - { - retry_count++; - result = errno; - LL_WARNS() << "Problem removing " << fullpath << " - errorcode: " - << result << " attempt " << retry_count << LL_ENDL; - - if(retry_count >= 5) - { - LL_WARNS() << "Failed to remove " << fullpath << LL_ENDL ; - return count ; - } - - ms_sleep(100); - } - else - { - if (retry_count) - { - LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL; - } - break; - } - } - count++; - } - return count; + S32 count = 0; + std::string filename; + std::string fullpath; + S32 result; + + // File masks starting with "/" will match nothing, so we consider them invalid. + if (LLStringUtil::startsWith(mask, getDirDelimiter())) + { + LL_WARNS() << "Invalid file mask: " << mask << LL_ENDL; + llassert(!"Invalid file mask"); + } + + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) + { + fullpath = add(dirname, filename); + + if(LLFile::isdir(fullpath)) + { + // skipping directory traversal filenames + count++; + continue; + } + + S32 retry_count = 0; + while (retry_count < 5) + { + if (0 != LLFile::remove(fullpath)) + { + retry_count++; + result = errno; + LL_WARNS() << "Problem removing " << fullpath << " - errorcode: " + << result << " attempt " << retry_count << LL_ENDL; + + if(retry_count >= 5) + { + LL_WARNS() << "Failed to remove " << fullpath << LL_ENDL ; + return count ; + } + + ms_sleep(100); + } + else + { + if (retry_count) + { + LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL; + } + break; + } + } + count++; + } + return count; } U32 LLDir::deleteDirAndContents(const std::string& dir_name) { //Removes the directory and its contents. Returns number of files deleted. - - U32 num_deleted = 0; - try - { + U32 num_deleted = 0; + + try + { #ifdef LL_WINDOWS // or BOOST_WINDOWS_API - boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name)); + boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name)); #else - boost::filesystem::path dir_path(dir_name); + boost::filesystem::path dir_path(dir_name); #endif - if (boost::filesystem::exists (dir_path)) - { - if (!boost::filesystem::is_empty (dir_path)) - { // Directory has content - num_deleted = boost::filesystem::remove_all (dir_path); - } - else - { // Directory is empty - boost::filesystem::remove (dir_path); - } - } - } - catch (boost::filesystem::filesystem_error &er) - { - LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; - } - return num_deleted; -} - -const std::string LLDir::findFile(const std::string &filename, - const std::string& searchPath1, - const std::string& searchPath2, - const std::string& searchPath3) const -{ - std::vector search_paths; - search_paths.push_back(searchPath1); - search_paths.push_back(searchPath2); - search_paths.push_back(searchPath3); - return findFile(filename, search_paths); + if (boost::filesystem::exists (dir_path)) + { + if (!boost::filesystem::is_empty (dir_path)) + { // Directory has content + num_deleted = boost::filesystem::remove_all (dir_path); + } + else + { // Directory is empty + boost::filesystem::remove (dir_path); + } + } + } + catch (boost::filesystem::filesystem_error &er) + { + LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; + } + return num_deleted; +} + +const std::string LLDir::findFile(const std::string &filename, + const std::string& searchPath1, + const std::string& searchPath2, + const std::string& searchPath3) const +{ + std::vector search_paths; + search_paths.push_back(searchPath1); + search_paths.push_back(searchPath2); + search_paths.push_back(searchPath3); + return findFile(filename, search_paths); } const std::string LLDir::findFile(const std::string& filename, const std::vector search_paths) const { - std::vector::const_iterator search_path_iter; - for (search_path_iter = search_paths.begin(); - search_path_iter != search_paths.end(); - ++search_path_iter) - { - if (!search_path_iter->empty()) - { - std::string filename_and_path = (*search_path_iter); - if (!filename.empty()) - { - filename_and_path += getDirDelimiter() + filename; - } - if (fileExists(filename_and_path)) - { - return filename_and_path; - } - } - } - return ""; + std::vector::const_iterator search_path_iter; + for (search_path_iter = search_paths.begin(); + search_path_iter != search_paths.end(); + ++search_path_iter) + { + if (!search_path_iter->empty()) + { + std::string filename_and_path = (*search_path_iter); + if (!filename.empty()) + { + filename_and_path += getDirDelimiter() + filename; + } + if (fileExists(filename_and_path)) + { + return filename_and_path; + } + } + } + return ""; } const std::string &LLDir::getExecutablePathAndName() const { - return mExecutablePathAndName; + return mExecutablePathAndName; } const std::string &LLDir::getExecutableFilename() const { - return mExecutableFilename; + return mExecutableFilename; } const std::string &LLDir::getExecutableDir() const { - return mExecutableDir; + return mExecutableDir; } const std::string &LLDir::getWorkingDir() const { - return mWorkingDir; + return mWorkingDir; } const std::string &LLDir::getAppName() const { - return mAppName; + return mAppName; } const std::string &LLDir::getAppRODataDir() const { - return mAppRODataDir; + return mAppRODataDir; } const std::string &LLDir::getOSUserDir() const { - return mOSUserDir; + return mOSUserDir; } const std::string &LLDir::getOSUserAppDir() const { - return mOSUserAppDir; + return mOSUserAppDir; } const std::string &LLDir::getLindenUserDir() const { - if (mLindenUserDir.empty()) - { - LL_DEBUGS() << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << LL_ENDL; - } + if (mLindenUserDir.empty()) + { + LL_DEBUGS() << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << LL_ENDL; + } - return mLindenUserDir; + return mLindenUserDir; } const std::string& LLDir::getChatLogsDir() const { - return mChatLogsDir; + return mChatLogsDir; } void LLDir::setDumpDir( const std::string& path ) @@ -326,14 +326,14 @@ const std::string &LLDir::getDumpDir() const { LLUUID uid; uid.generate(); - + sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "dump-" + uid.asString(); - dir_exists_or_crash(sDumpDir); + dir_exists_or_crash(sDumpDir); } - return LLDir::sDumpDir; + return LLDir::sDumpDir; } bool LLDir::dumpDirExists() const @@ -343,80 +343,80 @@ bool LLDir::dumpDirExists() const const std::string &LLDir::getPerAccountChatLogsDir() const { - return mPerAccountChatLogsDir; + return mPerAccountChatLogsDir; } const std::string &LLDir::getTempDir() const { - return mTempDir; + return mTempDir; } const std::string LLDir::getCacheDir(bool get_default) const { - if (mCacheDir.empty() || get_default) - { - if (!mDefaultCacheDir.empty()) - { // Set at startup - can't set here due to const API - return mDefaultCacheDir; - } - - std::string res = buildSLOSCacheDir(); - return res; - } - else - { - return mCacheDir; - } + if (mCacheDir.empty() || get_default) + { + if (!mDefaultCacheDir.empty()) + { // Set at startup - can't set here due to const API + return mDefaultCacheDir; + } + + std::string res = buildSLOSCacheDir(); + return res; + } + else + { + return mCacheDir; + } } // Return the default cache directory std::string LLDir::buildSLOSCacheDir() const { - std::string res; - if (getOSCacheDir().empty()) - { - if (getOSUserAppDir().empty()) - { - res = "data"; - } - else - { - res = add(getOSUserAppDir(), "cache"); - } - } - else - { - res = add(getOSCacheDir(), "SecondLife"); - } - return res; + std::string res; + if (getOSCacheDir().empty()) + { + if (getOSUserAppDir().empty()) + { + res = "data"; + } + else + { + res = add(getOSUserAppDir(), "cache"); + } + } + else + { + res = add(getOSCacheDir(), "SecondLife"); + } + return res; } const std::string &LLDir::getOSCacheDir() const { - return mOSCacheDir; + return mOSCacheDir; } const std::string &LLDir::getCAFile() const { - return mCAFile; + return mCAFile; } const std::string &LLDir::getDirDelimiter() const { - return mDirDelimiter; + return mDirDelimiter; } const std::string& LLDir::getDefaultSkinDir() const { - return mDefaultSkinDir; + return mDefaultSkinDir; } const std::string &LLDir::getSkinDir() const { - return mSkinDir; + return mSkinDir; } const std::string &LLDir::getUserDefaultSkinDir() const @@ -426,263 +426,263 @@ const std::string &LLDir::getUserDefaultSkinDir() const const std::string &LLDir::getUserSkinDir() const { - return mUserSkinDir; + return mUserSkinDir; } const std::string LLDir::getSkinBaseDir() const { - return mSkinBaseDir; + return mSkinBaseDir; } const std::string &LLDir::getLLPluginDir() const { - return mLLPluginDir; + return mLLPluginDir; } const std::string &LLDir::getUserName() const { - return mUserName; + return mUserName; } static std::string ELLPathToString(ELLPath location) { - typedef std::map ELLPathMap; + typedef std::map ELLPathMap; #define ENT(symbol) (symbol, #symbol) - static const ELLPathMap sMap = map_list_of - ENT(LL_PATH_NONE) - ENT(LL_PATH_USER_SETTINGS) - ENT(LL_PATH_APP_SETTINGS) - ENT(LL_PATH_PER_SL_ACCOUNT) // returns/expands to blank string if we don't know the account name yet - ENT(LL_PATH_CACHE) - ENT(LL_PATH_CHARACTER) - ENT(LL_PATH_HELP) - ENT(LL_PATH_LOGS) - ENT(LL_PATH_TEMP) - ENT(LL_PATH_SKINS) - ENT(LL_PATH_TOP_SKIN) - ENT(LL_PATH_CHAT_LOGS) - ENT(LL_PATH_PER_ACCOUNT_CHAT_LOGS) - ENT(LL_PATH_USER_SKIN) - ENT(LL_PATH_LOCAL_ASSETS) - ENT(LL_PATH_EXECUTABLE) - ENT(LL_PATH_DEFAULT_SKIN) - ENT(LL_PATH_FONTS) - ENT(LL_PATH_LAST) + static const ELLPathMap sMap = map_list_of + ENT(LL_PATH_NONE) + ENT(LL_PATH_USER_SETTINGS) + ENT(LL_PATH_APP_SETTINGS) + ENT(LL_PATH_PER_SL_ACCOUNT) // returns/expands to blank string if we don't know the account name yet + ENT(LL_PATH_CACHE) + ENT(LL_PATH_CHARACTER) + ENT(LL_PATH_HELP) + ENT(LL_PATH_LOGS) + ENT(LL_PATH_TEMP) + ENT(LL_PATH_SKINS) + ENT(LL_PATH_TOP_SKIN) + ENT(LL_PATH_CHAT_LOGS) + ENT(LL_PATH_PER_ACCOUNT_CHAT_LOGS) + ENT(LL_PATH_USER_SKIN) + ENT(LL_PATH_LOCAL_ASSETS) + ENT(LL_PATH_EXECUTABLE) + ENT(LL_PATH_DEFAULT_SKIN) + ENT(LL_PATH_FONTS) + ENT(LL_PATH_LAST) ENT(LL_PATH_SCRIPTS) - ; + ; #undef ENT - ELLPathMap::const_iterator found = sMap.find(location); - if (found != sMap.end()) - return found->second; - return STRINGIZE("Invalid ELLPath value " << location); + ELLPathMap::const_iterator found = sMap.find(location); + if (found != sMap.end()) + return found->second; + return STRINGIZE("Invalid ELLPath value " << location); } std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const { - return getExpandedFilename(location, "", filename); + return getExpandedFilename(location, "", filename); } std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir, const std::string& filename) const { - return getExpandedFilename(location, "", subdir, filename); + return getExpandedFilename(location, "", subdir, filename); } std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir1, const std::string& subdir2, const std::string& in_filename) const { - std::string prefix; - switch (location) - { - case LL_PATH_NONE: - // Do nothing - break; - - case LL_PATH_APP_SETTINGS: - prefix = add(getAppRODataDir(), "app_settings"); - break; - - case LL_PATH_CHARACTER: - prefix = add(getAppRODataDir(), "character"); - break; - - case LL_PATH_HELP: - prefix = "help"; - break; - - case LL_PATH_CACHE: - prefix = getCacheDir(); - break; - + std::string prefix; + switch (location) + { + case LL_PATH_NONE: + // Do nothing + break; + + case LL_PATH_APP_SETTINGS: + prefix = add(getAppRODataDir(), "app_settings"); + break; + + case LL_PATH_CHARACTER: + prefix = add(getAppRODataDir(), "character"); + break; + + case LL_PATH_HELP: + prefix = "help"; + break; + + case LL_PATH_CACHE: + prefix = getCacheDir(); + break; + case LL_PATH_DUMP: prefix=getDumpDir(); break; - - case LL_PATH_USER_SETTINGS: - prefix = add(getOSUserAppDir(), "user_settings"); - break; - - case LL_PATH_PER_SL_ACCOUNT: - prefix = getLindenUserDir(); - if (prefix.empty()) - { - // if we're asking for the per-SL-account directory but we haven't - // logged in yet (or otherwise don't know the account name from - // which to build this string), then intentionally return a blank - // string to the caller and skip the below warning about a blank - // prefix. - LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: " - << ELLPathToString(location) - << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "' => ''" << LL_ENDL; - return std::string(); - } - break; - - case LL_PATH_CHAT_LOGS: - prefix = getChatLogsDir(); - break; - - case LL_PATH_PER_ACCOUNT_CHAT_LOGS: - prefix = getPerAccountChatLogsDir(); - if (prefix.empty()) - { - // potentially directory was not set yet - // intentionally return a blank string to the caller - LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL; - return std::string(); - } - break; - - case LL_PATH_LOGS: - prefix = add(getOSUserAppDir(), "logs"); - break; - - case LL_PATH_TEMP: - prefix = getTempDir(); - break; - - case LL_PATH_TOP_SKIN: - prefix = getSkinDir(); - break; - - case LL_PATH_DEFAULT_SKIN: - prefix = getDefaultSkinDir(); - break; - - case LL_PATH_USER_SKIN: - prefix = getUserSkinDir(); - break; - - case LL_PATH_SKINS: - prefix = getSkinBaseDir(); - break; - - case LL_PATH_LOCAL_ASSETS: - prefix = add(getAppRODataDir(), "local_assets"); - break; - - case LL_PATH_EXECUTABLE: - prefix = getExecutableDir(); - break; - - case LL_PATH_FONTS: - prefix = add(getAppRODataDir(), "fonts"); - break; + + case LL_PATH_USER_SETTINGS: + prefix = add(getOSUserAppDir(), "user_settings"); + break; + + case LL_PATH_PER_SL_ACCOUNT: + prefix = getLindenUserDir(); + if (prefix.empty()) + { + // if we're asking for the per-SL-account directory but we haven't + // logged in yet (or otherwise don't know the account name from + // which to build this string), then intentionally return a blank + // string to the caller and skip the below warning about a blank + // prefix. + LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: " + << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "' => ''" << LL_ENDL; + return std::string(); + } + break; + + case LL_PATH_CHAT_LOGS: + prefix = getChatLogsDir(); + break; + + case LL_PATH_PER_ACCOUNT_CHAT_LOGS: + prefix = getPerAccountChatLogsDir(); + if (prefix.empty()) + { + // potentially directory was not set yet + // intentionally return a blank string to the caller + LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL; + return std::string(); + } + break; + + case LL_PATH_LOGS: + prefix = add(getOSUserAppDir(), "logs"); + break; + + case LL_PATH_TEMP: + prefix = getTempDir(); + break; + + case LL_PATH_TOP_SKIN: + prefix = getSkinDir(); + break; + + case LL_PATH_DEFAULT_SKIN: + prefix = getDefaultSkinDir(); + break; + + case LL_PATH_USER_SKIN: + prefix = getUserSkinDir(); + break; + + case LL_PATH_SKINS: + prefix = getSkinBaseDir(); + break; + + case LL_PATH_LOCAL_ASSETS: + prefix = add(getAppRODataDir(), "local_assets"); + break; + + case LL_PATH_EXECUTABLE: + prefix = getExecutableDir(); + break; + + case LL_PATH_FONTS: + prefix = add(getAppRODataDir(), "fonts"); + break; case LL_PATH_SCRIPTS: prefix = add(getAppRODataDir(), "scripts"); break; - - default: - llassert(0); - } - - if (prefix.empty()) - { - LL_WARNS() << ELLPathToString(location) - << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "': prefix is empty, possible bad filename" << LL_ENDL; - } - - std::string expanded_filename = add(prefix, subdir1, subdir2); - if (expanded_filename.empty() && in_filename.empty()) - { - return ""; - } - // Use explicit concatenation here instead of another add() call. Callers - // passing in_filename as "" expect to obtain a pathname ending with - // mDirSeparator so they can later directly concatenate with a specific - // filename. A caller using add() doesn't care, but there's still code - // loose in the system that uses std::string::operator+(). - expanded_filename += mDirDelimiter; - expanded_filename += in_filename; - - LL_DEBUGS("LLDir") << ELLPathToString(location) - << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "' => '" << expanded_filename << "'" << LL_ENDL; - return expanded_filename; + + default: + llassert(0); + } + + if (prefix.empty()) + { + LL_WARNS() << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "': prefix is empty, possible bad filename" << LL_ENDL; + } + + std::string expanded_filename = add(prefix, subdir1, subdir2); + if (expanded_filename.empty() && in_filename.empty()) + { + return ""; + } + // Use explicit concatenation here instead of another add() call. Callers + // passing in_filename as "" expect to obtain a pathname ending with + // mDirSeparator so they can later directly concatenate with a specific + // filename. A caller using add() doesn't care, but there's still code + // loose in the system that uses std::string::operator+(). + expanded_filename += mDirDelimiter; + expanded_filename += in_filename; + + LL_DEBUGS("LLDir") << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "' => '" << expanded_filename << "'" << LL_ENDL; + return expanded_filename; } std::string LLDir::getBaseFileName(const std::string& filepath, bool strip_exten) const { - std::size_t offset = filepath.find_last_of(getDirDelimiter()); - offset = (offset == std::string::npos) ? 0 : offset+1; - std::string res = filepath.substr(offset, std::string::npos); - if (strip_exten) - { - offset = res.find_last_of('.'); - if (offset != std::string::npos && - offset != 0) // if basename STARTS with '.', don't strip - { - res = res.substr(0, offset); - } - } - return res; + std::size_t offset = filepath.find_last_of(getDirDelimiter()); + offset = (offset == std::string::npos) ? 0 : offset+1; + std::string res = filepath.substr(offset, std::string::npos); + if (strip_exten) + { + offset = res.find_last_of('.'); + if (offset != std::string::npos && + offset != 0) // if basename STARTS with '.', don't strip + { + res = res.substr(0, offset); + } + } + return res; } std::string LLDir::getDirName(const std::string& filepath) const { - std::size_t offset = filepath.find_last_of(getDirDelimiter()); - S32 len = (offset == std::string::npos) ? 0 : offset; - std::string dirname = filepath.substr(0, len); - return dirname; + std::size_t offset = filepath.find_last_of(getDirDelimiter()); + S32 len = (offset == std::string::npos) ? 0 : offset; + std::string dirname = filepath.substr(0, len); + return dirname; } std::string LLDir::getExtension(const std::string& filepath) const { - if (filepath.empty()) - return std::string(); - std::string basename = getBaseFileName(filepath, false); - std::size_t offset = basename.find_last_of('.'); - std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1); - LLStringUtil::toLower(exten); - return exten; + if (filepath.empty()) + return std::string(); + std::string basename = getBaseFileName(filepath, false); + std::size_t offset = basename.find_last_of('.'); + std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1); + LLStringUtil::toLower(exten); + return exten; } std::string LLDir::findSkinnedFilenameBaseLang(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint) const + const std::string &filename, + ESkinConstraint constraint) const { - // This implementation is basically just as described in the declaration comments. - std::vector found(findSkinnedFilenames(subdir, filename, constraint)); - if (found.empty()) - { - return ""; - } - return found.front(); + // This implementation is basically just as described in the declaration comments. + std::vector found(findSkinnedFilenames(subdir, filename, constraint)); + if (found.empty()) + { + return ""; + } + return found.front(); } std::string LLDir::findSkinnedFilename(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint) const + const std::string &filename, + ESkinConstraint constraint) const { - // This implementation is basically just as described in the declaration comments. - std::vector found(findSkinnedFilenames(subdir, filename, constraint)); - if (found.empty()) - { - return ""; - } - return found.back(); + // This implementation is basically just as described in the declaration comments. + std::vector found(findSkinnedFilenames(subdir, filename, constraint)); + if (found.empty()) + { + return ""; + } + return found.back(); } // This method exists because the two code paths for @@ -691,210 +691,210 @@ std::string LLDir::findSkinnedFilename(const std::string &subdir, // difference is in the body of the inner loop. template void LLDir::walkSearchSkinDirs(const std::string& subdir, - const std::vector& subsubdirs, - const std::string& filename, - const FUNCTION& function) const -{ - for (const std::string& skindir : mSearchSkinDirs) - { - std::string subdir_path(add(skindir, subdir)); - for (const std::string& subsubdir : subsubdirs) - { - std::string full_path(add(subdir_path, subsubdir, filename)); - if (fileExists(full_path)) - { - function(subsubdir, full_path); - } - } - } + const std::vector& subsubdirs, + const std::string& filename, + const FUNCTION& function) const +{ + for (const std::string& skindir : mSearchSkinDirs) + { + std::string subdir_path(add(skindir, subdir)); + for (const std::string& subsubdir : subsubdirs) + { + std::string full_path(add(subdir_path, subsubdir, filename)); + if (fileExists(full_path)) + { + function(subsubdir, full_path); + } + } + } } // ridiculous little helper function that should go away when we can use lambda inline void push_back(std::vector& vector, const std::string& value) { - vector.push_back(value); + vector.push_back(value); } typedef std::map StringMap; // ridiculous little helper function that should go away when we can use lambda inline void store_in_map(StringMap& map, const std::string& key, const std::string& value) { - map[key] = value; + map[key] = value; } std::vector LLDir::findSkinnedFilenames(const std::string& subdir, - const std::string& filename, - ESkinConstraint constraint) const -{ - // Recognize subdirs that have no localization. - static const std::set sUnlocalized = list_of - ("") // top-level directory not localized - ("textures") // textures not localized - ; - - LL_DEBUGS("LLDir") << "subdir '" << subdir << "', filename '" << filename - << "', constraint " - << ((constraint == CURRENT_SKIN)? "CURRENT_SKIN" : "ALL_SKINS") - << LL_ENDL; - - // Build results vector. - std::vector results; - // Disallow filenames that may escape subdir - if (filename.find("..") != std::string::npos) - { - LL_WARNS("LLDir") << "Ignoring potentially relative filename '" << filename << "'" << LL_ENDL; - return results; - } - - // Cache the default language directory for each subdir we've encountered. - // A cache entry whose value is the empty string means "not localized, - // don't bother checking again." - static StringMap sLocalized; - - // Check whether we've already discovered if this subdir is localized. - StringMap::const_iterator found = sLocalized.find(subdir); - if (found == sLocalized.end()) - { - // We have not yet determined that. Is it one of the subdirs "known" - // to be unlocalized? - if (sUnlocalized.find(subdir) != sUnlocalized.end()) - { - // This subdir is known to be unlocalized. Remember that. - found = sLocalized.insert(StringMap::value_type(subdir, "")).first; - } - else - { - // We do not recognize this subdir. Investigate. - std::string subdir_path(add(getDefaultSkinDir(), subdir)); - if (fileExists(add(subdir_path, "en"))) - { - // defaultSkinDir/subdir contains subdir "en". That's our - // default language; this subdir is localized. - found = sLocalized.insert(StringMap::value_type(subdir, "en")).first; - } - else if (fileExists(add(subdir_path, "en-us"))) - { - // defaultSkinDir/subdir contains subdir "en-us" but not "en". - // Set as default language; this subdir is localized. - found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first; - } - else - { - // defaultSkinDir/subdir contains neither "en" nor "en-us". - // Assume it's not localized. Remember that assumption. - found = sLocalized.insert(StringMap::value_type(subdir, "")).first; - } - } - } - // Every code path above should have resulted in 'found' becoming a valid - // iterator to an entry in sLocalized. - llassert(found != sLocalized.end()); - - // Now -- is this subdir localized, or not? The answer determines what - // subdirectories we check (under subdir) for the requested filename. - std::vector subsubdirs; - if (found->second.empty()) - { - // subdir is not localized. filename should be located directly within it. - subsubdirs.push_back(""); - } - else - { - // subdir is localized, and found->second is the default language - // directory within it. Check both the default language and the - // current language -- if it differs from the default, of course. - subsubdirs.push_back(found->second); - if (mLanguage != found->second) - { - subsubdirs.push_back(mLanguage); - } - } - - // The process we use depends on 'constraint'. - if (constraint != CURRENT_SKIN) // meaning ALL_SKINS - { - // ALL_SKINS is simpler: just return every pathname generated by - // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its - // FUNCTION the subsubdir as well as the full pathname. We just want - // the full pathname. - walkSearchSkinDirs(subdir, subsubdirs, filename, - boost::bind(push_back, boost::ref(results), _2)); - } - else // CURRENT_SKIN - { - // CURRENT_SKIN turns out to be a bit of a misnomer because we might - // still return files from two different skins. In any case, this - // value of 'constraint' means we will return at most two paths: one - // for the default language, one for the current language (supposing - // those differ). - // It is important to allow a user to override only the localization - // for a particular file, for all viewer installs, without also - // overriding the default-language file. - // It is important to allow a user to override only the default- - // language file, for all viewer installs, without also overriding the - // applicable localization of that file. - // Therefore, treat the default language and the current language as - // two separate cases. For each, capture the most-specialized file - // that exists. - // Use a map keyed by subsubdir (i.e. language code). This allows us - // to handle the case of a single subsubdirs entry with the same logic - // that handles two. For every real file path generated by - // walkSearchSkinDirs(), update the map entry for its subsubdir. - StringMap path_for; - walkSearchSkinDirs(subdir, subsubdirs, filename, - boost::bind(store_in_map, boost::ref(path_for), _1, _2)); - // Now that we have a path for each of the default language and the - // current language, copy them -- in proper order -- into results. - // Don't drive this by walking the map itself: it matters that we - // generate results in the same order as subsubdirs. - for (const std::string& subsubdir : subsubdirs) - { - StringMap::const_iterator found(path_for.find(subsubdir)); - if (found != path_for.end()) - { - results.push_back(found->second); - } - } - } - - LL_DEBUGS("LLDir") << empty; - const char* comma = ""; - for (const std::string& path : results) - { - LL_CONT << comma << "'" << path << "'"; - comma = ", "; - } - LL_CONT << LL_ENDL; - - return results; + const std::string& filename, + ESkinConstraint constraint) const +{ + // Recognize subdirs that have no localization. + static const std::set sUnlocalized = list_of + ("") // top-level directory not localized + ("textures") // textures not localized + ; + + LL_DEBUGS("LLDir") << "subdir '" << subdir << "', filename '" << filename + << "', constraint " + << ((constraint == CURRENT_SKIN)? "CURRENT_SKIN" : "ALL_SKINS") + << LL_ENDL; + + // Build results vector. + std::vector results; + // Disallow filenames that may escape subdir + if (filename.find("..") != std::string::npos) + { + LL_WARNS("LLDir") << "Ignoring potentially relative filename '" << filename << "'" << LL_ENDL; + return results; + } + + // Cache the default language directory for each subdir we've encountered. + // A cache entry whose value is the empty string means "not localized, + // don't bother checking again." + static StringMap sLocalized; + + // Check whether we've already discovered if this subdir is localized. + StringMap::const_iterator found = sLocalized.find(subdir); + if (found == sLocalized.end()) + { + // We have not yet determined that. Is it one of the subdirs "known" + // to be unlocalized? + if (sUnlocalized.find(subdir) != sUnlocalized.end()) + { + // This subdir is known to be unlocalized. Remember that. + found = sLocalized.insert(StringMap::value_type(subdir, "")).first; + } + else + { + // We do not recognize this subdir. Investigate. + std::string subdir_path(add(getDefaultSkinDir(), subdir)); + if (fileExists(add(subdir_path, "en"))) + { + // defaultSkinDir/subdir contains subdir "en". That's our + // default language; this subdir is localized. + found = sLocalized.insert(StringMap::value_type(subdir, "en")).first; + } + else if (fileExists(add(subdir_path, "en-us"))) + { + // defaultSkinDir/subdir contains subdir "en-us" but not "en". + // Set as default language; this subdir is localized. + found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first; + } + else + { + // defaultSkinDir/subdir contains neither "en" nor "en-us". + // Assume it's not localized. Remember that assumption. + found = sLocalized.insert(StringMap::value_type(subdir, "")).first; + } + } + } + // Every code path above should have resulted in 'found' becoming a valid + // iterator to an entry in sLocalized. + llassert(found != sLocalized.end()); + + // Now -- is this subdir localized, or not? The answer determines what + // subdirectories we check (under subdir) for the requested filename. + std::vector subsubdirs; + if (found->second.empty()) + { + // subdir is not localized. filename should be located directly within it. + subsubdirs.push_back(""); + } + else + { + // subdir is localized, and found->second is the default language + // directory within it. Check both the default language and the + // current language -- if it differs from the default, of course. + subsubdirs.push_back(found->second); + if (mLanguage != found->second) + { + subsubdirs.push_back(mLanguage); + } + } + + // The process we use depends on 'constraint'. + if (constraint != CURRENT_SKIN) // meaning ALL_SKINS + { + // ALL_SKINS is simpler: just return every pathname generated by + // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its + // FUNCTION the subsubdir as well as the full pathname. We just want + // the full pathname. + walkSearchSkinDirs(subdir, subsubdirs, filename, + boost::bind(push_back, boost::ref(results), _2)); + } + else // CURRENT_SKIN + { + // CURRENT_SKIN turns out to be a bit of a misnomer because we might + // still return files from two different skins. In any case, this + // value of 'constraint' means we will return at most two paths: one + // for the default language, one for the current language (supposing + // those differ). + // It is important to allow a user to override only the localization + // for a particular file, for all viewer installs, without also + // overriding the default-language file. + // It is important to allow a user to override only the default- + // language file, for all viewer installs, without also overriding the + // applicable localization of that file. + // Therefore, treat the default language and the current language as + // two separate cases. For each, capture the most-specialized file + // that exists. + // Use a map keyed by subsubdir (i.e. language code). This allows us + // to handle the case of a single subsubdirs entry with the same logic + // that handles two. For every real file path generated by + // walkSearchSkinDirs(), update the map entry for its subsubdir. + StringMap path_for; + walkSearchSkinDirs(subdir, subsubdirs, filename, + boost::bind(store_in_map, boost::ref(path_for), _1, _2)); + // Now that we have a path for each of the default language and the + // current language, copy them -- in proper order -- into results. + // Don't drive this by walking the map itself: it matters that we + // generate results in the same order as subsubdirs. + for (const std::string& subsubdir : subsubdirs) + { + StringMap::const_iterator found(path_for.find(subsubdir)); + if (found != path_for.end()) + { + results.push_back(found->second); + } + } + } + + LL_DEBUGS("LLDir") << empty; + const char* comma = ""; + for (const std::string& path : results) + { + LL_CONT << comma << "'" << path << "'"; + comma = ", "; + } + LL_CONT << LL_ENDL; + + return results; } std::string LLDir::getTempFilename() const { - LLUUID random_uuid; - std::string uuid_str; + LLUUID random_uuid; + std::string uuid_str; - random_uuid.generate(); - random_uuid.toString(uuid_str); + random_uuid.generate(); + random_uuid.toString(uuid_str); - return add(getTempDir(), uuid_str + ".tmp"); + return add(getTempDir(), uuid_str + ".tmp"); } // static std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) { - std::string name(uncleanFileName); - const std::string illegalChars(getForbiddenFileChars()); - // replace any illegal file chars with and underscore '_' - for( unsigned int i = 0; i < illegalChars.length(); i++ ) - { - int j = -1; - while((j = name.find(illegalChars[i])) > -1) - { - name[j] = '_'; - } - } - return name; + std::string name(uncleanFileName); + const std::string illegalChars(getForbiddenFileChars()); + // replace any illegal file chars with and underscore '_' + for( unsigned int i = 0; i < illegalChars.length(); i++ ) + { + int j = -1; + while((j = name.find(illegalChars[i])) > -1) + { + name[j] = '_'; + } + } + return name; } std::string LLDir::getDumpLogsDirPath(const std::string &file_name) @@ -905,241 +905,241 @@ std::string LLDir::getDumpLogsDirPath(const std::string &file_name) // static std::string LLDir::getForbiddenFileChars() { - return "\\/:*?\"<>|"; + return "\\/:*?\"<>|"; } void LLDir::setLindenUserDir(const std::string &username) { - // if the username isn't set, that's bad - if (!username.empty()) - { - // some platforms have case-sensitive filesystems, so be - // utterly consistent with our firstname/lastname case. - std::string userlower(username); - LLStringUtil::toLower(userlower); - LLStringUtil::replaceChar(userlower, ' ', '_'); - mLindenUserDir = add(getOSUserAppDir(), userlower); - } - else - { - LL_ERRS() << "NULL name for LLDir::setLindenUserDir" << LL_ENDL; - } + // if the username isn't set, that's bad + if (!username.empty()) + { + // some platforms have case-sensitive filesystems, so be + // utterly consistent with our firstname/lastname case. + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); + mLindenUserDir = add(getOSUserAppDir(), userlower); + } + else + { + LL_ERRS() << "NULL name for LLDir::setLindenUserDir" << LL_ENDL; + } - dumpCurrentDirectories(); + dumpCurrentDirectories(); } void LLDir::setChatLogsDir(const std::string &path) { - if (!path.empty() ) - { - mChatLogsDir = path; - } - else - { - LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL; - } + if (!path.empty() ) + { + mChatLogsDir = path; + } + else + { + LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL; + } } void LLDir::updatePerAccountChatLogsDir() { - mPerAccountChatLogsDir = add(getChatLogsDir(), mUserName); + mPerAccountChatLogsDir = add(getChatLogsDir(), mUserName); } void LLDir::setPerAccountChatLogsDir(const std::string &username) { - // if both first and last aren't set, assume we're grabbing the cached dir - if (!username.empty()) - { - // some platforms have case-sensitive filesystems, so be - // utterly consistent with our firstname/lastname case. - std::string userlower(username); - LLStringUtil::toLower(userlower); - LLStringUtil::replaceChar(userlower, ' ', '_'); - - mUserName = userlower; - updatePerAccountChatLogsDir(); - } - else - { - LL_ERRS() << "NULL name for LLDir::setPerAccountChatLogsDir" << LL_ENDL; - } + // if both first and last aren't set, assume we're grabbing the cached dir + if (!username.empty()) + { + // some platforms have case-sensitive filesystems, so be + // utterly consistent with our firstname/lastname case. + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); + + mUserName = userlower; + updatePerAccountChatLogsDir(); + } + else + { + LL_ERRS() << "NULL name for LLDir::setPerAccountChatLogsDir" << LL_ENDL; + } } void LLDir::setSkinFolder(const std::string &skin_folder, const std::string& language) { - LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'" - << LL_ENDL; - mSkinName = skin_folder; - mLanguage = language; - - // This method is called multiple times during viewer initialization. Each - // time it's called, reset mSearchSkinDirs. - mSearchSkinDirs.clear(); - - // base skin which is used as fallback for all skinned files - // e.g. c:\program files\secondlife\skins\default - mDefaultSkinDir = getSkinBaseDir(); - append(mDefaultSkinDir, "default"); - // This is always the most general of the search skin directories. - addSearchSkinDir(mDefaultSkinDir); - - mSkinDir = getSkinBaseDir(); - append(mSkinDir, skin_folder); - // Next level of generality is a skin installed with the viewer. - addSearchSkinDir(mSkinDir); - - // user modifications to skins, current and default - // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle - mUserSkinDir = getOSUserAppDir(); - append(mUserSkinDir, "skins"); - mUserDefaultSkinDir = mUserSkinDir; - append(mUserDefaultSkinDir, "default"); - append(mUserSkinDir, skin_folder); - // Next level of generality is user modifications to default skin... - addSearchSkinDir(mUserDefaultSkinDir); - // then user-defined skins. - addSearchSkinDir(mUserSkinDir); + LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'" + << LL_ENDL; + mSkinName = skin_folder; + mLanguage = language; + + // This method is called multiple times during viewer initialization. Each + // time it's called, reset mSearchSkinDirs. + mSearchSkinDirs.clear(); + + // base skin which is used as fallback for all skinned files + // e.g. c:\program files\secondlife\skins\default + mDefaultSkinDir = getSkinBaseDir(); + append(mDefaultSkinDir, "default"); + // This is always the most general of the search skin directories. + addSearchSkinDir(mDefaultSkinDir); + + mSkinDir = getSkinBaseDir(); + append(mSkinDir, skin_folder); + // Next level of generality is a skin installed with the viewer. + addSearchSkinDir(mSkinDir); + + // user modifications to skins, current and default + // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle + mUserSkinDir = getOSUserAppDir(); + append(mUserSkinDir, "skins"); + mUserDefaultSkinDir = mUserSkinDir; + append(mUserDefaultSkinDir, "default"); + append(mUserSkinDir, skin_folder); + // Next level of generality is user modifications to default skin... + addSearchSkinDir(mUserDefaultSkinDir); + // then user-defined skins. + addSearchSkinDir(mUserSkinDir); } void LLDir::addSearchSkinDir(const std::string& skindir) { - if (std::find(mSearchSkinDirs.begin(), mSearchSkinDirs.end(), skindir) == mSearchSkinDirs.end()) - { - LL_DEBUGS("LLDir") << "search skin: '" << skindir << "'" << LL_ENDL; - mSearchSkinDirs.push_back(skindir); - } + if (std::find(mSearchSkinDirs.begin(), mSearchSkinDirs.end(), skindir) == mSearchSkinDirs.end()) + { + LL_DEBUGS("LLDir") << "search skin: '" << skindir << "'" << LL_ENDL; + mSearchSkinDirs.push_back(skindir); + } } std::string LLDir::getSkinFolder() const { - return mSkinName; + return mSkinName; } std::string LLDir::getLanguage() const { - return mLanguage; + return mLanguage; } bool LLDir::setCacheDir(const std::string &path) { - if (path.empty() ) - { - // reset to default - mCacheDir = ""; - return true; - } - else - { - LLFile::mkdir(path); - std::string tempname = add(path, "temp"); - LLFILE* file = LLFile::fopen(tempname,"wt"); - if (file) - { - fclose(file); - LLFile::remove(tempname); - mCacheDir = path; - return true; - } - return false; - } + if (path.empty() ) + { + // reset to default + mCacheDir = ""; + return true; + } + else + { + LLFile::mkdir(path); + std::string tempname = add(path, "temp"); + LLFILE* file = LLFile::fopen(tempname,"wt"); + if (file) + { + fclose(file); + LLFile::remove(tempname); + mCacheDir = path; + return true; + } + return false; + } } void LLDir::dumpCurrentDirectories(LLError::ELevel level) { - LL_VLOGS(level, "AppInit","Directories") << "Current Directories:" << LL_ENDL; - - LL_VLOGS(level, "AppInit", "Directories") << " CurPath: " << getCurPath() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " AppName: " << getAppName() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " TempDir: " << getTempDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " CAFile: " << getCAFile() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; - LL_VLOGS(level, "AppInit", "Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; + LL_VLOGS(level, "AppInit","Directories") << "Current Directories:" << LL_ENDL; + + LL_VLOGS(level, "AppInit", "Directories") << " CurPath: " << getCurPath() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " AppName: " << getAppName() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " TempDir: " << getTempDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " CAFile: " << getCAFile() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; + LL_VLOGS(level, "AppInit", "Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; } void LLDir::append(std::string& destpath, const std::string& name) const { - // Delegate question of whether we need a separator to helper method. - SepOff sepoff(needSep(destpath, name)); - if (sepoff.first) // do we need a separator? - { - destpath += mDirDelimiter; - } - // If destpath ends with a separator, AND name starts with one, skip - // name's leading separator. - destpath += name.substr(sepoff.second); + // Delegate question of whether we need a separator to helper method. + SepOff sepoff(needSep(destpath, name)); + if (sepoff.first) // do we need a separator? + { + destpath += mDirDelimiter; + } + // If destpath ends with a separator, AND name starts with one, skip + // name's leading separator. + destpath += name.substr(sepoff.second); } LLDir::SepOff LLDir::needSep(const std::string& path, const std::string& name) const { - if (path.empty() || name.empty()) - { - // If either path or name are empty, we do not need a separator - // between them. - return SepOff(false, 0); - } - // Here we know path and name are both non-empty. But if path already ends - // with a separator, or if name already starts with a separator, we need - // not add one. - std::string::size_type seplen(mDirDelimiter.length()); - bool path_ends_sep(path.substr(path.length() - seplen) == mDirDelimiter); - bool name_starts_sep(name.substr(0, seplen) == mDirDelimiter); - if ((! path_ends_sep) && (! name_starts_sep)) - { - // If neither path nor name brings a separator to the junction, then - // we need one. - return SepOff(true, 0); - } - if (path_ends_sep && name_starts_sep) - { - // But if BOTH path and name bring a separator, we need not add one. - // Moreover, we should actually skip the leading separator of 'name'. - return SepOff(false, (unsigned short)seplen); - } - // Here we know that either path_ends_sep or name_starts_sep is true -- - // but not both. So don't add a separator, and don't skip any characters: - // simple concatenation will do the trick. - return SepOff(false, 0); + if (path.empty() || name.empty()) + { + // If either path or name are empty, we do not need a separator + // between them. + return SepOff(false, 0); + } + // Here we know path and name are both non-empty. But if path already ends + // with a separator, or if name already starts with a separator, we need + // not add one. + std::string::size_type seplen(mDirDelimiter.length()); + bool path_ends_sep(path.substr(path.length() - seplen) == mDirDelimiter); + bool name_starts_sep(name.substr(0, seplen) == mDirDelimiter); + if ((! path_ends_sep) && (! name_starts_sep)) + { + // If neither path nor name brings a separator to the junction, then + // we need one. + return SepOff(true, 0); + } + if (path_ends_sep && name_starts_sep) + { + // But if BOTH path and name bring a separator, we need not add one. + // Moreover, we should actually skip the leading separator of 'name'. + return SepOff(false, (unsigned short)seplen); + } + // Here we know that either path_ends_sep or name_starts_sep is true -- + // but not both. So don't add a separator, and don't skip any characters: + // simple concatenation will do the trick. + return SepOff(false, 0); } void dir_exists_or_crash(const std::string &dir_name) { #if LL_WINDOWS - // *FIX: lame - it doesn't do the same thing on windows. not so - // important since we don't deploy simulator to windows boxes. - LLFile::mkdir(dir_name, 0700); + // *FIX: lame - it doesn't do the same thing on windows. not so + // important since we don't deploy simulator to windows boxes. + LLFile::mkdir(dir_name, 0700); #else - struct stat dir_stat; - if(0 != LLFile::stat(dir_name, &dir_stat)) - { - S32 stat_rv = errno; - if(ENOENT == stat_rv) - { - if(0 != LLFile::mkdir(dir_name, 0700)) // octal - { - LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL; - } - } - else - { - LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv - << LL_ENDL; - } - } - else - { - // data_dir exists, make sure it's a directory. - if(!S_ISDIR(dir_stat.st_mode)) - { - LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL; - } - } + struct stat dir_stat; + if(0 != LLFile::stat(dir_name, &dir_stat)) + { + S32 stat_rv = errno; + if(ENOENT == stat_rv) + { + if(0 != LLFile::mkdir(dir_name, 0700)) // octal + { + LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL; + } + } + else + { + LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv + << LL_ENDL; + } + } + else + { + // data_dir exists, make sure it's a directory. + if(!S_ISDIR(dir_stat.st_mode)) + { + LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL; + } + } #endif } diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h index 7d418159d1..560f63d40d 100644 --- a/indra/llfilesystem/lldir.h +++ b/indra/llfilesystem/lldir.h @@ -1,25 +1,25 @@ -/** +/** * @file lldir.h * @brief Definition of directory utilities class * * $LicenseInfo:firstyear=2000&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$ */ @@ -30,246 +30,246 @@ // these numbers are read from settings_files.xml, so we need to be explicit typedef enum ELLPath { - LL_PATH_NONE = 0, - LL_PATH_USER_SETTINGS = 1, - LL_PATH_APP_SETTINGS = 2, - LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet - LL_PATH_CACHE = 4, - LL_PATH_CHARACTER = 5, - LL_PATH_HELP = 6, - LL_PATH_LOGS = 7, - LL_PATH_TEMP = 8, - LL_PATH_SKINS = 9, - LL_PATH_TOP_SKIN = 10, - LL_PATH_CHAT_LOGS = 11, - LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12, - LL_PATH_USER_SKIN = 14, - LL_PATH_LOCAL_ASSETS = 15, - LL_PATH_EXECUTABLE = 16, - LL_PATH_DEFAULT_SKIN = 17, - LL_PATH_FONTS = 18, + LL_PATH_NONE = 0, + LL_PATH_USER_SETTINGS = 1, + LL_PATH_APP_SETTINGS = 2, + LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet + LL_PATH_CACHE = 4, + LL_PATH_CHARACTER = 5, + LL_PATH_HELP = 6, + LL_PATH_LOGS = 7, + LL_PATH_TEMP = 8, + LL_PATH_SKINS = 9, + LL_PATH_TOP_SKIN = 10, + LL_PATH_CHAT_LOGS = 11, + LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12, + LL_PATH_USER_SKIN = 14, + LL_PATH_LOCAL_ASSETS = 15, + LL_PATH_EXECUTABLE = 16, + LL_PATH_DEFAULT_SKIN = 17, + LL_PATH_FONTS = 18, LL_PATH_DUMP = 19, LL_PATH_SCRIPTS = 20, - LL_PATH_LAST + LL_PATH_LAST } ELLPath; /// Directory operations class LLDir { public: - LLDir(); - virtual ~LLDir(); + LLDir(); + virtual ~LLDir(); - // app_name - Usually SecondLife, used for creating settings directories - // in OS-specific location, such as C:\Documents and Settings - // app_read_only_data_dir - Usually the source code directory, used - // for test applications to read newview data files. - virtual void initAppDirs(const std::string &app_name, - const std::string& app_read_only_data_dir = "") = 0; + // app_name - Usually SecondLife, used for creating settings directories + // in OS-specific location, such as C:\Documents and Settings + // app_read_only_data_dir - Usually the source code directory, used + // for test applications to read newview data files. + virtual void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir = "") = 0; - virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); + virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); U32 deleteDirAndContents(const std::string& dir_name); std::vector getFilesInDir(const std::string &dirname); // pure virtual functions - virtual std::string getCurPath() = 0; - virtual bool fileExists(const std::string &filename) const = 0; + virtual std::string getCurPath() = 0; + virtual bool fileExists(const std::string &filename) const = 0; - const std::string findFile(const std::string& filename, const std::vector filenames) const; - const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; + const std::string findFile(const std::string& filename, const std::vector filenames) const; + const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; - virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell - virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') + virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell + virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') - const std::string &getExecutablePathAndName() const; // Full pathname of the executable - const std::string &getAppName() const; // install directory under progams/ ie "SecondLife" - const std::string &getExecutableDir() const; // Directory where the executable is located - const std::string &getExecutableFilename() const;// Filename of .exe - const std::string &getWorkingDir() const; // Current working directory - const std::string &getAppRODataDir() const; // Location of read-only data files - const std::string &getOSUserDir() const; // Location of the os-specific user dir - const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir - const std::string &getLindenUserDir() const; // Location of the Linden user dir. - const std::string &getChatLogsDir() const; // Location of the chat logs dir. - const std::string &getDumpDir() const; // Location of the per-run dump dir. - bool dumpDirExists() const; - const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. - const std::string &getTempDir() const; // Common temporary directory - const std::string getCacheDir(bool get_default = false) const; // Location of the cache. - const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string) - const std::string &getCAFile() const; // File containing TLS certificate authorities - const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') - const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default - const std::string &getSkinDir() const; // User-specified skin folder. - const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin - const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin - const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins - const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell - const std::string &getUserName() const; + const std::string &getExecutablePathAndName() const; // Full pathname of the executable + const std::string &getAppName() const; // install directory under progams/ ie "SecondLife" + const std::string &getExecutableDir() const; // Directory where the executable is located + const std::string &getExecutableFilename() const;// Filename of .exe + const std::string &getWorkingDir() const; // Current working directory + const std::string &getAppRODataDir() const; // Location of read-only data files + const std::string &getOSUserDir() const; // Location of the os-specific user dir + const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir + const std::string &getLindenUserDir() const; // Location of the Linden user dir. + const std::string &getChatLogsDir() const; // Location of the chat logs dir. + const std::string &getDumpDir() const; // Location of the per-run dump dir. + bool dumpDirExists() const; + const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. + const std::string &getTempDir() const; // Common temporary directory + const std::string getCacheDir(bool get_default = false) const; // Location of the cache. + const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string) + const std::string &getCAFile() const; // File containing TLS certificate authorities + const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') + const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default + const std::string &getSkinDir() const; // User-specified skin folder. + const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin + const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin + const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins + const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell + const std::string &getUserName() const; - // Expanded filename - std::string getExpandedFilename(ELLPath location, const std::string &filename) const; - std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const; - std::string getExpandedFilename(ELLPath location, const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; + // Expanded filename + std::string getExpandedFilename(ELLPath location, const std::string &filename) const; + std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const; + std::string getExpandedFilename(ELLPath location, const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; - // Base and Directory name extraction - std::string getBaseFileName(const std::string& filepath, bool strip_exten = false) const; - std::string getDirName(const std::string& filepath) const; - std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav" + // Base and Directory name extraction + std::string getBaseFileName(const std::string& filepath, bool strip_exten = false) const; + std::string getDirName(const std::string& filepath) const; + std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav" - // these methods search the various skin paths for the specified file in the following order: - // getUserSkinDir(), getUserDefaultSkinDir(), getSkinDir(), getDefaultSkinDir() - /// param value for findSkinnedFilenames(), explained below - enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS }; - /** - * Given a filename within skin, return an ordered sequence of paths to - * search. Nonexistent files will be filtered out -- which means that the - * vector might be empty. - * - * @param subdir Identify top-level skin subdirectory by passing one of - * LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file - * lives under "textures" subtree), LLDir::SKINBASE (file lives at top - * level of skin subdirectory). - * @param filename Desired filename within subdir within skin, e.g. - * "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language. - * @param constraint Callers perform two different kinds of processing. - * When fetching a XUI file, for instance, the existence of @a filename in - * the specified skin completely supercedes any @a filename in the default - * skin. For that case, leave the default @a constraint=CURRENT_SKIN. The - * returned vector will contain only - * ".../current_skin/xui/en/filename", - * ".../current_skin/xui/current_language/filename". - * But for (e.g.) "strings.xml", we want a given skin to be able to - * override only specific entries from the default skin. Any string not - * defined in the specified skin will be sought in the default skin. For - * that case, pass @a constraint=ALL_SKINS. The returned vector will - * contain at least ".../default/xui/en/strings.xml", - * ".../default/xui/current_language/strings.xml", - * ".../current_skin/xui/en/strings.xml", - * ".../current_skin/xui/current_language/strings.xml". - */ - std::vector findSkinnedFilenames(const std::string& subdir, - const std::string& filename, - ESkinConstraint constraint=CURRENT_SKIN) const; - /// Values for findSkinnedFilenames(subdir) parameter - static const char *XUI, *TEXTURES, *SKINBASE; - /** - * Return the base-language pathname from findSkinnedFilenames(), or - * the empty string if no such file exists. Parameters are identical to - * findSkinnedFilenames(). This is shorthand for capturing the vector - * returned by findSkinnedFilenames(), checking for empty() and then - * returning front(). - */ - std::string findSkinnedFilenameBaseLang(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint=CURRENT_SKIN) const; - /** - * Return the "most localized" pathname from findSkinnedFilenames(), or - * the empty string if no such file exists. Parameters are identical to - * findSkinnedFilenames(). This is shorthand for capturing the vector - * returned by findSkinnedFilenames(), checking for empty() and then - * returning back(). - */ - std::string findSkinnedFilename(const std::string &subdir, - const std::string &filename, - ESkinConstraint constraint=CURRENT_SKIN) const; + // these methods search the various skin paths for the specified file in the following order: + // getUserSkinDir(), getUserDefaultSkinDir(), getSkinDir(), getDefaultSkinDir() + /// param value for findSkinnedFilenames(), explained below + enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS }; + /** + * Given a filename within skin, return an ordered sequence of paths to + * search. Nonexistent files will be filtered out -- which means that the + * vector might be empty. + * + * @param subdir Identify top-level skin subdirectory by passing one of + * LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file + * lives under "textures" subtree), LLDir::SKINBASE (file lives at top + * level of skin subdirectory). + * @param filename Desired filename within subdir within skin, e.g. + * "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language. + * @param constraint Callers perform two different kinds of processing. + * When fetching a XUI file, for instance, the existence of @a filename in + * the specified skin completely supercedes any @a filename in the default + * skin. For that case, leave the default @a constraint=CURRENT_SKIN. The + * returned vector will contain only + * ".../current_skin/xui/en/filename", + * ".../current_skin/xui/current_language/filename". + * But for (e.g.) "strings.xml", we want a given skin to be able to + * override only specific entries from the default skin. Any string not + * defined in the specified skin will be sought in the default skin. For + * that case, pass @a constraint=ALL_SKINS. The returned vector will + * contain at least ".../default/xui/en/strings.xml", + * ".../default/xui/current_language/strings.xml", + * ".../current_skin/xui/en/strings.xml", + * ".../current_skin/xui/current_language/strings.xml". + */ + std::vector findSkinnedFilenames(const std::string& subdir, + const std::string& filename, + ESkinConstraint constraint=CURRENT_SKIN) const; + /// Values for findSkinnedFilenames(subdir) parameter + static const char *XUI, *TEXTURES, *SKINBASE; + /** + * Return the base-language pathname from findSkinnedFilenames(), or + * the empty string if no such file exists. Parameters are identical to + * findSkinnedFilenames(). This is shorthand for capturing the vector + * returned by findSkinnedFilenames(), checking for empty() and then + * returning front(). + */ + std::string findSkinnedFilenameBaseLang(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint=CURRENT_SKIN) const; + /** + * Return the "most localized" pathname from findSkinnedFilenames(), or + * the empty string if no such file exists. Parameters are identical to + * findSkinnedFilenames(). This is shorthand for capturing the vector + * returned by findSkinnedFilenames(), checking for empty() and then + * returning back(). + */ + std::string findSkinnedFilename(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint=CURRENT_SKIN) const; - // random filename in common temporary directory - std::string getTempFilename() const; + // random filename in common temporary directory + std::string getTempFilename() const; static std::string getDumpLogsDirPath(const std::string &file_name = ""); - // For producing safe download file names from potentially unsafe ones - static std::string getScrubbedFileName(const std::string uncleanFileName); - static std::string getForbiddenFileChars(); + // For producing safe download file names from potentially unsafe ones + static std::string getScrubbedFileName(const std::string uncleanFileName); + static std::string getForbiddenFileChars(); void setDumpDir( const std::string& path ); - virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir - virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory. - virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir - virtual void setSkinFolder(const std::string &skin_folder, const std::string& language); - virtual std::string getSkinFolder() const; - virtual std::string getLanguage() const; - virtual bool setCacheDir(const std::string &path); - virtual void updatePerAccountChatLogsDir(); + virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir + virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory. + virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir + virtual void setSkinFolder(const std::string &skin_folder, const std::string& language); + virtual std::string getSkinFolder() const; + virtual std::string getLanguage() const; + virtual bool setCacheDir(const std::string &path); + virtual void updatePerAccountChatLogsDir(); - virtual void dumpCurrentDirectories(LLError::ELevel level = LLError::LEVEL_DEBUG); + virtual void dumpCurrentDirectories(LLError::ELevel level = LLError::LEVEL_DEBUG); - // Utility routine - std::string buildSLOSCacheDir() const; + // Utility routine + std::string buildSLOSCacheDir() const; - /// Append specified @a name to @a destpath, separated by getDirDelimiter() - /// if both are non-empty. - void append(std::string& destpath, const std::string& name) const; - /// Variadic form: append @a name0 and @a name1 and arbitrary other @a - /// names to @a destpath, separated by getDirDelimiter() as needed. - template - void append(std::string& destpath, const std::string& name0, const std::string& name1, - const NAMES& ... names) const - { - // In a typical recursion case, we'd accept (destpath, name0, names). - // We accept (destpath, name0, name1, names) because it's important to - // delegate the two-argument case to the non-template implementation. - append(destpath, name0); - append(destpath, name1, names...); - } + /// Append specified @a name to @a destpath, separated by getDirDelimiter() + /// if both are non-empty. + void append(std::string& destpath, const std::string& name) const; + /// Variadic form: append @a name0 and @a name1 and arbitrary other @a + /// names to @a destpath, separated by getDirDelimiter() as needed. + template + void append(std::string& destpath, const std::string& name0, const std::string& name1, + const NAMES& ... names) const + { + // In a typical recursion case, we'd accept (destpath, name0, names). + // We accept (destpath, name0, name1, names) because it's important to + // delegate the two-argument case to the non-template implementation. + append(destpath, name0); + append(destpath, name1, names...); + } - /// Append specified @a names to @a path, separated by getDirDelimiter() - /// as needed. Return result, leaving @a path unmodified. - template - std::string add(const std::string& path, const NAMES& ... names) const - { - std::string destpath(path); - append(destpath, names...); - return destpath; - } + /// Append specified @a names to @a path, separated by getDirDelimiter() + /// as needed. Return result, leaving @a path unmodified. + template + std::string add(const std::string& path, const NAMES& ... names) const + { + std::string destpath(path); + append(destpath, names...); + return destpath; + } protected: - // Does an add() or append() call need a directory delimiter? - typedef std::pair SepOff; - SepOff needSep(const std::string& path, const std::string& name) const; - // build mSearchSkinDirs without adding duplicates - void addSearchSkinDir(const std::string& skindir); + // Does an add() or append() call need a directory delimiter? + typedef std::pair SepOff; + SepOff needSep(const std::string& path, const std::string& name) const; + // build mSearchSkinDirs without adding duplicates + void addSearchSkinDir(const std::string& skindir); - // Internal to findSkinnedFilenames() - template - void walkSearchSkinDirs(const std::string& subdir, - const std::vector& subsubdirs, - const std::string& filename, - const FUNCTION& function) const; + // Internal to findSkinnedFilenames() + template + void walkSearchSkinDirs(const std::string& subdir, + const std::vector& subsubdirs, + const std::string& filename, + const FUNCTION& function) const; - std::string mAppName; // install directory under progams/ ie "SecondLife" - std::string mExecutablePathAndName; // full path + Filename of .exe - std::string mExecutableFilename; // Filename of .exe - std::string mExecutableDir; // Location of executable - std::string mWorkingDir; // Current working directory - std::string mAppRODataDir; // Location for static app data - std::string mOSUserDir; // OS Specific user directory - std::string mOSUserAppDir; // OS Specific user app directory - std::string mLindenUserDir; // Location for Linden user-specific data - std::string mPerAccountChatLogsDir; // Location for chat logs. - std::string mChatLogsDir; // Location for chat logs. - std::string mCAFile; // Location of the TLS certificate authority PEM file. - std::string mTempDir; - std::string mCacheDir; // cache directory as set by user preference - std::string mDefaultCacheDir; // default cache diretory - std::string mOSCacheDir; // operating system cache dir - std::string mDirDelimiter; - std::string mSkinName; // caller-specified skin name - std::string mSkinBaseDir; // Base for skins paths. - std::string mDefaultSkinDir; // Location for default skin info. - std::string mSkinDir; // Location for current skin info. - std::string mUserDefaultSkinDir; // Location for default skin info. - std::string mUserSkinDir; // Location for user-modified skin info. - // Skin directories to search, most general to most specific. This order - // works well for composing fine-grained files, in which an individual item - // in a specific file overrides the corresponding item in more general - // files. Of course, for a file-level search, iterate backwards. - std::vector mSearchSkinDirs; - std::string mLanguage; // Current viewer language - std::string mLLPluginDir; // Location for plugins and plugin shell + std::string mAppName; // install directory under progams/ ie "SecondLife" + std::string mExecutablePathAndName; // full path + Filename of .exe + std::string mExecutableFilename; // Filename of .exe + std::string mExecutableDir; // Location of executable + std::string mWorkingDir; // Current working directory + std::string mAppRODataDir; // Location for static app data + std::string mOSUserDir; // OS Specific user directory + std::string mOSUserAppDir; // OS Specific user app directory + std::string mLindenUserDir; // Location for Linden user-specific data + std::string mPerAccountChatLogsDir; // Location for chat logs. + std::string mChatLogsDir; // Location for chat logs. + std::string mCAFile; // Location of the TLS certificate authority PEM file. + std::string mTempDir; + std::string mCacheDir; // cache directory as set by user preference + std::string mDefaultCacheDir; // default cache diretory + std::string mOSCacheDir; // operating system cache dir + std::string mDirDelimiter; + std::string mSkinName; // caller-specified skin name + std::string mSkinBaseDir; // Base for skins paths. + std::string mDefaultSkinDir; // Location for default skin info. + std::string mSkinDir; // Location for current skin info. + std::string mUserDefaultSkinDir; // Location for default skin info. + std::string mUserSkinDir; // Location for user-modified skin info. + // Skin directories to search, most general to most specific. This order + // works well for composing fine-grained files, in which an individual item + // in a specific file overrides the corresponding item in more general + // files. Of course, for a file-level search, iterate backwards. + std::vector mSearchSkinDirs; + std::string mLanguage; // Current viewer language + std::string mLLPluginDir; // Location for plugins and plugin shell static std::string sDumpDir; // Per-run crash report subdir of log directory. - std::string mUserName; // Current user name + std::string mUserName; // Current user name }; void dir_exists_or_crash(const std::string &dir_name); diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp index cecb8b2edb..5ffe1d6e4f 100644 --- a/indra/llmath/tests/mathmisc_test.cpp +++ b/indra/llmath/tests/mathmisc_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file math.cpp * @author Phoenix * @date 2005-09-26 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&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$ */ @@ -40,704 +40,704 @@ namespace tut { - struct math_data - { - }; - typedef test_group math_test; - typedef math_test::object math_object; - tut::math_test tm("BasicLindenMath"); - - template<> template<> - void math_object::test<1>() - { - S32 val = 89543; - val = llabs(val); - ensure("integer absolute value 1", (89543 == val)); - val = -500; - val = llabs(val); - ensure("integer absolute value 2", (500 == val)); - } - - template<> template<> - void math_object::test<2>() - { - F32 val = -2583.4f; - val = llabs(val); - ensure("float absolute value 1", (2583.4f == val)); - val = 430903.f; - val = llabs(val); - ensure("float absolute value 2", (430903.f == val)); - } - - template<> template<> - void math_object::test<3>() - { - F64 val = 387439393.987329839; - val = llabs(val); - ensure("double absolute value 1", (387439393.987329839 == val)); - val = -8937843.9394878; - val = llabs(val); - ensure("double absolute value 2", (8937843.9394878 == val)); - } - - template<> template<> - void math_object::test<4>() - { - F32 val = 430903.9f; - S32 val1 = lltrunc(val); - ensure("float truncate value 1", (430903 == val1)); - val = -2303.9f; - val1 = lltrunc(val); - ensure("float truncate value 2", (-2303 == val1)); - } - - template<> template<> - void math_object::test<5>() - { - F64 val = 387439393.987329839 ; - S32 val1 = lltrunc(val); - ensure("float truncate value 1", (387439393 == val1)); - val = -387439393.987329839; - val1 = lltrunc(val); - ensure("float truncate value 2", (-387439393 == val1)); - } - - template<> template<> - void math_object::test<6>() - { - F32 val = 430903.2f; - S32 val1 = llfloor(val); - ensure("float llfloor value 1", (430903 == val1)); - val = -430903.9f; - val1 = llfloor(val); - ensure("float llfloor value 2", (-430904 == val1)); - } - - template<> template<> - void math_object::test<7>() - { - F32 val = 430903.2f; - S32 val1 = llceil(val); - ensure("float llceil value 1", (430904 == val1)); - val = -430903.9f; - val1 = llceil(val); - ensure("float llceil value 2", (-430903 == val1)); - } - - template<> template<> - void math_object::test<8>() - { - F32 val = 430903.2f; - S32 val1 = ll_round(val); - ensure("float ll_round value 1", (430903 == val1)); - val = -430903.9f; - val1 = ll_round(val); - ensure("float ll_round value 2", (-430904 == val1)); - } - - template<> template<> - void math_object::test<9>() - { - F32 val = 430905.2654f, nearest = 100.f; - val = ll_round(val, nearest); - ensure("float ll_round value 1", (430900 == val)); - val = -430905.2654f, nearest = 10.f; - val = ll_round(val, nearest); - ensure("float ll_round value 1", (-430910 == val)); - } - - template<> template<> - void math_object::test<10>() - { - F64 val = 430905.2654, nearest = 100.0; - val = ll_round(val, nearest); - ensure("double ll_round value 1", (430900 == val)); - val = -430905.2654, nearest = 10.0; - val = ll_round(val, nearest); - ensure("double ll_round value 1", (-430910.00000 == val)); - } - - template<> template<> - void math_object::test<11>() - { - const F32 F_PI = 3.1415926535897932384626433832795f; - F32 angle = 3506.f; - angle = llsimple_angle(angle); - ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); - angle = -431.f; - angle = llsimple_angle(angle); - ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); - } + struct math_data + { + }; + typedef test_group math_test; + typedef math_test::object math_object; + tut::math_test tm("BasicLindenMath"); + + template<> template<> + void math_object::test<1>() + { + S32 val = 89543; + val = llabs(val); + ensure("integer absolute value 1", (89543 == val)); + val = -500; + val = llabs(val); + ensure("integer absolute value 2", (500 == val)); + } + + template<> template<> + void math_object::test<2>() + { + F32 val = -2583.4f; + val = llabs(val); + ensure("float absolute value 1", (2583.4f == val)); + val = 430903.f; + val = llabs(val); + ensure("float absolute value 2", (430903.f == val)); + } + + template<> template<> + void math_object::test<3>() + { + F64 val = 387439393.987329839; + val = llabs(val); + ensure("double absolute value 1", (387439393.987329839 == val)); + val = -8937843.9394878; + val = llabs(val); + ensure("double absolute value 2", (8937843.9394878 == val)); + } + + template<> template<> + void math_object::test<4>() + { + F32 val = 430903.9f; + S32 val1 = lltrunc(val); + ensure("float truncate value 1", (430903 == val1)); + val = -2303.9f; + val1 = lltrunc(val); + ensure("float truncate value 2", (-2303 == val1)); + } + + template<> template<> + void math_object::test<5>() + { + F64 val = 387439393.987329839 ; + S32 val1 = lltrunc(val); + ensure("float truncate value 1", (387439393 == val1)); + val = -387439393.987329839; + val1 = lltrunc(val); + ensure("float truncate value 2", (-387439393 == val1)); + } + + template<> template<> + void math_object::test<6>() + { + F32 val = 430903.2f; + S32 val1 = llfloor(val); + ensure("float llfloor value 1", (430903 == val1)); + val = -430903.9f; + val1 = llfloor(val); + ensure("float llfloor value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<7>() + { + F32 val = 430903.2f; + S32 val1 = llceil(val); + ensure("float llceil value 1", (430904 == val1)); + val = -430903.9f; + val1 = llceil(val); + ensure("float llceil value 2", (-430903 == val1)); + } + + template<> template<> + void math_object::test<8>() + { + F32 val = 430903.2f; + S32 val1 = ll_round(val); + ensure("float ll_round value 1", (430903 == val1)); + val = -430903.9f; + val1 = ll_round(val); + ensure("float ll_round value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<9>() + { + F32 val = 430905.2654f, nearest = 100.f; + val = ll_round(val, nearest); + ensure("float ll_round value 1", (430900 == val)); + val = -430905.2654f, nearest = 10.f; + val = ll_round(val, nearest); + ensure("float ll_round value 1", (-430910 == val)); + } + + template<> template<> + void math_object::test<10>() + { + F64 val = 430905.2654, nearest = 100.0; + val = ll_round(val, nearest); + ensure("double ll_round value 1", (430900 == val)); + val = -430905.2654, nearest = 10.0; + val = ll_round(val, nearest); + ensure("double ll_round value 1", (-430910.00000 == val)); + } + + template<> template<> + void math_object::test<11>() + { + const F32 F_PI = 3.1415926535897932384626433832795f; + F32 angle = 3506.f; + angle = llsimple_angle(angle); + ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); + angle = -431.f; + angle = llsimple_angle(angle); + ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); + } } namespace tut { - struct uuid_data - { - LLUUID id; - }; - typedef test_group uuid_test; - typedef uuid_test::object uuid_object; - tut::uuid_test tu("LLUUID"); - - template<> template<> - void uuid_object::test<1>() - { - ensure("uuid null", id.isNull()); - id.generate(); - ensure("generate not null", id.notNull()); - id.setNull(); - ensure("set null", id.isNull()); - } - - template<> template<> - void uuid_object::test<2>() - { - id.generate(); - LLUUID a(id); - ensure_equals("copy equal", id, a); - a.generate(); - ensure_not_equals("generate not equal", id, a); - a = id; - ensure_equals("assignment equal", id, a); - } - - template<> template<> - void uuid_object::test<3>() - { - id.generate(); - LLUUID copy(id); - LLUUID mask; - mask.generate(); - copy ^= mask; - ensure_not_equals("mask not equal", id, copy); - copy ^= mask; - ensure_equals("mask back", id, copy); - } - - template<> template<> - void uuid_object::test<4>() - { - id.generate(); - std::string id_str = id.asString(); - LLUUID copy(id_str.c_str()); - ensure_equals("string serialization", id, copy); - } - + struct uuid_data + { + LLUUID id; + }; + typedef test_group uuid_test; + typedef uuid_test::object uuid_object; + tut::uuid_test tu("LLUUID"); + + template<> template<> + void uuid_object::test<1>() + { + ensure("uuid null", id.isNull()); + id.generate(); + ensure("generate not null", id.notNull()); + id.setNull(); + ensure("set null", id.isNull()); + } + + template<> template<> + void uuid_object::test<2>() + { + id.generate(); + LLUUID a(id); + ensure_equals("copy equal", id, a); + a.generate(); + ensure_not_equals("generate not equal", id, a); + a = id; + ensure_equals("assignment equal", id, a); + } + + template<> template<> + void uuid_object::test<3>() + { + id.generate(); + LLUUID copy(id); + LLUUID mask; + mask.generate(); + copy ^= mask; + ensure_not_equals("mask not equal", id, copy); + copy ^= mask; + ensure_equals("mask back", id, copy); + } + + template<> template<> + void uuid_object::test<4>() + { + id.generate(); + std::string id_str = id.asString(); + LLUUID copy(id_str.c_str()); + ensure_equals("string serialization", id, copy); + } + } namespace tut { - struct crc_data - { - }; - typedef test_group crc_test; - typedef crc_test::object crc_object; - tut::crc_test tc("LLCrc"); - - template<> template<> - void crc_object::test<1>() - { - /* Test buffer update and individual char update */ - const char TEST_BUFFER[] = "hello &#$)$&Nd0"; - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1); - char* rh = (char*)TEST_BUFFER; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - ensure_equals("crc update 1", c1.getCRC(), c2.getCRC()); - } - - template<> template<> - void crc_object::test<2>() - { - /* Test mixing of buffer and individual char update */ - const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$"; - const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds"; - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1); - char* rh = (char*)TEST_BUFFER2; - while(*rh != '\0') - { - c1.update(*rh); - ++rh; - } - - rh = (char*)TEST_BUFFER1; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1); - - ensure_equals("crc update 2", c1.getCRC(), c2.getCRC()); - } + struct crc_data + { + }; + typedef test_group crc_test; + typedef crc_test::object crc_object; + tut::crc_test tc("LLCrc"); + + template<> template<> + void crc_object::test<1>() + { + /* Test buffer update and individual char update */ + const char TEST_BUFFER[] = "hello &#$)$&Nd0"; + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1); + char* rh = (char*)TEST_BUFFER; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + ensure_equals("crc update 1", c1.getCRC(), c2.getCRC()); + } + + template<> template<> + void crc_object::test<2>() + { + /* Test mixing of buffer and individual char update */ + const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$"; + const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds"; + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1); + char* rh = (char*)TEST_BUFFER2; + while(*rh != '\0') + { + c1.update(*rh); + ++rh; + } + + rh = (char*)TEST_BUFFER1; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1); + + ensure_equals("crc update 2", c1.getCRC(), c2.getCRC()); + } } namespace tut { - struct sphere_data - { - }; - typedef test_group sphere_test; - typedef sphere_test::object sphere_object; - tut::sphere_test tsphere("LLSphere"); - - template<> template<> - void sphere_object::test<1>() - { - // test LLSphere::contains() and ::overlaps() - S32 number_of_tests = 10; - for (S32 test = 0; test < number_of_tests; ++test) - { - LLVector3 first_center(1.f, 1.f, 1.f); - F32 first_radius = 3.f; - LLSphere first_sphere( first_center, first_radius ); - - F32 half_millimeter = 0.0005f; - LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); - direction.normalize(); - - F32 distance = ll_frand(first_radius - 2.f * half_millimeter); - LLVector3 second_center = first_center + distance * direction; - F32 second_radius = first_radius - distance - half_millimeter; - LLSphere second_sphere( second_center, second_radius ); - ensure("first sphere should contain the second", first_sphere.contains(second_sphere)); - ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); - - distance = first_radius + ll_frand(first_radius); - second_center = first_center + distance * direction; - second_radius = distance - first_radius + half_millimeter; - second_sphere.set( second_center, second_radius ); - ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); - ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); - - distance = first_radius + ll_frand(first_radius) + half_millimeter; - second_center = first_center + distance * direction; - second_radius = distance - first_radius - half_millimeter; - second_sphere.set( second_center, second_radius ); - ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); - ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere)); - } - } - - template<> template<> - void sphere_object::test<2>() - { - skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only."); - - // test LLSphere::getBoundingSphere() - S32 number_of_tests = 100; - S32 number_of_spheres = 10; - F32 sphere_center_range = 32.f; - F32 sphere_radius_range = 5.f; - - for (S32 test = 0; test < number_of_tests; ++test) - { - // gegnerate a bunch of random sphere - std::vector< LLSphere > sphere_list; - for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count) - { - LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); - direction.normalize(); - F32 distance = ll_frand(sphere_center_range); - LLVector3 center = distance * direction; - F32 radius = ll_frand(sphere_radius_range); - LLSphere sphere( center, radius ); - sphere_list.push_back(sphere); - } - - // compute the bounding sphere - LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list); - - // make sure all spheres are inside the bounding sphere - { - std::vector< LLSphere >::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr)); - } - } - - // TODO -- improve LLSphere::getBoundingSphere() to the point where - // we can reduce the 'expansion' in the two tests below to about - // 2 mm or less - - F32 expansion = 0.005f; - // move all spheres out a little bit - // and count how many are NOT contained - { - std::vector< LLVector3 > uncontained_directions; - std::vector< LLSphere >::iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); - direction.normalize(); - - sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction ); - if (! bounding_sphere.contains( *sphere_itr ) ) - { - uncontained_directions.push_back(direction); - } - } - ensure("when moving spheres out there should be at least two uncontained spheres", - uncontained_directions.size() > 1); - - /* TODO -- when the bounding sphere algorithm is improved we can open up this test - * at the moment it occasionally fails when the sphere collection is tight and small - * (2 meters or less) - if (2 == uncontained_directions.size() ) - { - // if there were only two uncontained spheres then - // the two directions should be nearly opposite - F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; - ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); - } - */ - } - - // compute the new bounding sphere - bounding_sphere = LLSphere::getBoundingSphere(sphere_list); - - // increase the size of all spheres a little bit - // and count how many are NOT contained - { - std::vector< LLVector3 > uncontained_directions; - std::vector< LLSphere >::iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); - direction.normalize(); - - sphere_itr->setRadius( sphere_itr->getRadius() + expansion ); - if (! bounding_sphere.contains( *sphere_itr ) ) - { - uncontained_directions.push_back(direction); - } - } - ensure("when boosting sphere radii there should be at least two uncontained spheres", - uncontained_directions.size() > 1); - - /* TODO -- when the bounding sphere algorithm is improved we can open up this test - * at the moment it occasionally fails when the sphere collection is tight and small - * (2 meters or less) - if (2 == uncontained_directions.size() ) - { - // if there were only two uncontained spheres then - // the two directions should be nearly opposite - F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; - ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); - } - */ - } - } - } + struct sphere_data + { + }; + typedef test_group sphere_test; + typedef sphere_test::object sphere_object; + tut::sphere_test tsphere("LLSphere"); + + template<> template<> + void sphere_object::test<1>() + { + // test LLSphere::contains() and ::overlaps() + S32 number_of_tests = 10; + for (S32 test = 0; test < number_of_tests; ++test) + { + LLVector3 first_center(1.f, 1.f, 1.f); + F32 first_radius = 3.f; + LLSphere first_sphere( first_center, first_radius ); + + F32 half_millimeter = 0.0005f; + LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); + direction.normalize(); + + F32 distance = ll_frand(first_radius - 2.f * half_millimeter); + LLVector3 second_center = first_center + distance * direction; + F32 second_radius = first_radius - distance - half_millimeter; + LLSphere second_sphere( second_center, second_radius ); + ensure("first sphere should contain the second", first_sphere.contains(second_sphere)); + ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); + + distance = first_radius + ll_frand(first_radius); + second_center = first_center + distance * direction; + second_radius = distance - first_radius + half_millimeter; + second_sphere.set( second_center, second_radius ); + ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); + ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); + + distance = first_radius + ll_frand(first_radius) + half_millimeter; + second_center = first_center + distance * direction; + second_radius = distance - first_radius - half_millimeter; + second_sphere.set( second_center, second_radius ); + ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); + ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere)); + } + } + + template<> template<> + void sphere_object::test<2>() + { + skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only."); + + // test LLSphere::getBoundingSphere() + S32 number_of_tests = 100; + S32 number_of_spheres = 10; + F32 sphere_center_range = 32.f; + F32 sphere_radius_range = 5.f; + + for (S32 test = 0; test < number_of_tests; ++test) + { + // gegnerate a bunch of random sphere + std::vector< LLSphere > sphere_list; + for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count) + { + LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); + direction.normalize(); + F32 distance = ll_frand(sphere_center_range); + LLVector3 center = distance * direction; + F32 radius = ll_frand(sphere_radius_range); + LLSphere sphere( center, radius ); + sphere_list.push_back(sphere); + } + + // compute the bounding sphere + LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list); + + // make sure all spheres are inside the bounding sphere + { + std::vector< LLSphere >::const_iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr)); + } + } + + // TODO -- improve LLSphere::getBoundingSphere() to the point where + // we can reduce the 'expansion' in the two tests below to about + // 2 mm or less + + F32 expansion = 0.005f; + // move all spheres out a little bit + // and count how many are NOT contained + { + std::vector< LLVector3 > uncontained_directions; + std::vector< LLSphere >::iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); + direction.normalize(); + + sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction ); + if (! bounding_sphere.contains( *sphere_itr ) ) + { + uncontained_directions.push_back(direction); + } + } + ensure("when moving spheres out there should be at least two uncontained spheres", + uncontained_directions.size() > 1); + + /* TODO -- when the bounding sphere algorithm is improved we can open up this test + * at the moment it occasionally fails when the sphere collection is tight and small + * (2 meters or less) + if (2 == uncontained_directions.size() ) + { + // if there were only two uncontained spheres then + // the two directions should be nearly opposite + F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; + ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); + } + */ + } + + // compute the new bounding sphere + bounding_sphere = LLSphere::getBoundingSphere(sphere_list); + + // increase the size of all spheres a little bit + // and count how many are NOT contained + { + std::vector< LLVector3 > uncontained_directions; + std::vector< LLSphere >::iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); + direction.normalize(); + + sphere_itr->setRadius( sphere_itr->getRadius() + expansion ); + if (! bounding_sphere.contains( *sphere_itr ) ) + { + uncontained_directions.push_back(direction); + } + } + ensure("when boosting sphere radii there should be at least two uncontained spheres", + uncontained_directions.size() > 1); + + /* TODO -- when the bounding sphere algorithm is improved we can open up this test + * at the moment it occasionally fails when the sphere collection is tight and small + * (2 meters or less) + if (2 == uncontained_directions.size() ) + { + // if there were only two uncontained spheres then + // the two directions should be nearly opposite + F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; + ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); + } + */ + } + } + } } namespace tut { - F32 SMALL_RADIUS = 1.0f; - F32 MEDIUM_RADIUS = 5.0f; - F32 LARGE_RADIUS = 10.0f; - - struct line_data - { - }; - typedef test_group line_test; - typedef line_test::object line_object; - tut::line_test tline("LLLine"); - - template<> template<> - void line_object::test<1>() - { - // this is a test for LLLine::intersects(point) which returns TRUE - // if the line passes within some tolerance of point - - // these tests will have some floating point error, - // so we need to specify how much error is ok - F32 allowable_relative_error = 0.00001f; - S32 number_of_tests = 100; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate some random point to be on the line - LLVector3 point_on_line( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_line.normalize(); - point_on_line *= ll_frand(LARGE_RADIUS); - - // generate some random point to "intersect" - LLVector3 random_direction ( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - random_direction.normalize(); - - LLVector3 random_offset( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - random_offset.normalize(); - random_offset *= ll_frand(SMALL_RADIUS); - - LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction - + random_offset; - - // compute the axis of approach (a unit vector between the points) - LLVector3 axis_of_approach = point - point_on_line; - axis_of_approach.normalize(); - - // compute the direction of the the first line (perp to axis_of_approach) - LLVector3 first_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - first_dir.normalize(); - F32 dot = first_dir * axis_of_approach; - first_dir -= dot * axis_of_approach; // subtract component parallel to axis - first_dir.normalize(); - - // construct the line - LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir; - LLLine line(another_point_on_line, point_on_line); - - // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS - F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS; - test_radius += (LARGE_RADIUS * allowable_relative_error); - ensure("line should pass near intersection point", line.intersects(point, test_radius)); - - test_radius = allowable_relative_error * (point - point_on_line).length(); - ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius)); - } - } - - template<> template<> - void line_object::test<2>() - { + F32 SMALL_RADIUS = 1.0f; + F32 MEDIUM_RADIUS = 5.0f; + F32 LARGE_RADIUS = 10.0f; + + struct line_data + { + }; + typedef test_group line_test; + typedef line_test::object line_object; + tut::line_test tline("LLLine"); + + template<> template<> + void line_object::test<1>() + { + // this is a test for LLLine::intersects(point) which returns TRUE + // if the line passes within some tolerance of point + + // these tests will have some floating point error, + // so we need to specify how much error is ok + F32 allowable_relative_error = 0.00001f; + S32 number_of_tests = 100; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate some random point to be on the line + LLVector3 point_on_line( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_line.normalize(); + point_on_line *= ll_frand(LARGE_RADIUS); + + // generate some random point to "intersect" + LLVector3 random_direction ( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + random_direction.normalize(); + + LLVector3 random_offset( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + random_offset.normalize(); + random_offset *= ll_frand(SMALL_RADIUS); + + LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction + + random_offset; + + // compute the axis of approach (a unit vector between the points) + LLVector3 axis_of_approach = point - point_on_line; + axis_of_approach.normalize(); + + // compute the direction of the the first line (perp to axis_of_approach) + LLVector3 first_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + first_dir.normalize(); + F32 dot = first_dir * axis_of_approach; + first_dir -= dot * axis_of_approach; // subtract component parallel to axis + first_dir.normalize(); + + // construct the line + LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir; + LLLine line(another_point_on_line, point_on_line); + + // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS + F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS; + test_radius += (LARGE_RADIUS * allowable_relative_error); + ensure("line should pass near intersection point", line.intersects(point, test_radius)); + + test_radius = allowable_relative_error * (point - point_on_line).length(); + ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius)); + } + } + + template<> template<> + void line_object::test<2>() + { /* These tests fail intermittently on all platforms - see DEV-16600 Commenting this out until dev has time to investigate. - - // this is a test for LLLine::nearestApproach(LLLIne) method - // which computes the point on a line nearest another line - - // these tests will have some floating point error, - // so we need to specify how much error is ok - // TODO -- make nearestApproach() algorithm more accurate so - // we can tighten the allowable_error. Most tests are tighter - // than one milimeter, however when doing randomized testing - // you can walk into inaccurate cases. - F32 allowable_relative_error = 0.001f; - S32 number_of_tests = 100; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate two points to be our known nearest approaches - LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - some_point.normalize(); - some_point *= ll_frand(LARGE_RADIUS); - - LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - another_point.normalize(); - another_point *= ll_frand(LARGE_RADIUS); - - // compute the axis of approach (a unit vector between the points) - LLVector3 axis_of_approach = another_point - some_point; - axis_of_approach.normalize(); - - // compute the direction of the the first line (perp to axis_of_approach) - LLVector3 first_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - F32 dot = first_dir * axis_of_approach; - first_dir -= dot * axis_of_approach; // subtract component parallel to axis - first_dir.normalize(); // normalize - - // compute the direction of the the second line - LLVector3 second_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - dot = second_dir * axis_of_approach; - second_dir -= dot * axis_of_approach; - second_dir.normalize(); - - // make sure the lines aren't too parallel, - dot = fabsf(first_dir * second_dir); - if (dot > 0.99f) - { - // skip this test, we're not interested in testing - // the intractible cases - continue; - } - - // construct the lines - LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir; - LLLine first_line(first_point, some_point); - - LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir; - LLLine second_line(second_point, another_point); - - // compute the points of nearest approach - LLVector3 some_computed_point = first_line.nearestApproach(second_line); - LLVector3 another_computed_point = second_line.nearestApproach(first_line); - - // compute the error - F32 first_error = (some_point - some_computed_point).length(); - F32 scale = llmax((some_point - another_point).length(), some_point.length()); - scale = llmax(scale, another_point.length()); - scale = llmax(scale, 1.f); - F32 first_relative_error = first_error / scale; - - F32 second_error = (another_point - another_computed_point).length(); - F32 second_relative_error = second_error / scale; - - //if (first_relative_error > allowable_relative_error) - //{ - // std::cout << "first_error = " << first_error - // << " first_relative_error = " << first_relative_error - // << " scale = " << scale - // << " dir_dot = " << (first_dir * second_dir) - // << std::endl; - //} - //if (second_relative_error > allowable_relative_error) - //{ - // std::cout << "second_error = " << second_error - // << " second_relative_error = " << second_relative_error - // << " scale = " << scale - // << " dist = " << (some_point - another_point).length() - // << " dir_dot = " << (first_dir * second_dir) - // << std::endl; - //} - - // test that the errors are small - - ensure("first line should accurately compute its closest approach", - first_relative_error <= allowable_relative_error); - ensure("second line should accurately compute its closest approach", - second_relative_error <= allowable_relative_error); - } + + // this is a test for LLLine::nearestApproach(LLLIne) method + // which computes the point on a line nearest another line + + // these tests will have some floating point error, + // so we need to specify how much error is ok + // TODO -- make nearestApproach() algorithm more accurate so + // we can tighten the allowable_error. Most tests are tighter + // than one milimeter, however when doing randomized testing + // you can walk into inaccurate cases. + F32 allowable_relative_error = 0.001f; + S32 number_of_tests = 100; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate two points to be our known nearest approaches + LLVector3 some_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + some_point.normalize(); + some_point *= ll_frand(LARGE_RADIUS); + + LLVector3 another_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + another_point.normalize(); + another_point *= ll_frand(LARGE_RADIUS); + + // compute the axis of approach (a unit vector between the points) + LLVector3 axis_of_approach = another_point - some_point; + axis_of_approach.normalize(); + + // compute the direction of the the first line (perp to axis_of_approach) + LLVector3 first_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + F32 dot = first_dir * axis_of_approach; + first_dir -= dot * axis_of_approach; // subtract component parallel to axis + first_dir.normalize(); // normalize + + // compute the direction of the the second line + LLVector3 second_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + dot = second_dir * axis_of_approach; + second_dir -= dot * axis_of_approach; + second_dir.normalize(); + + // make sure the lines aren't too parallel, + dot = fabsf(first_dir * second_dir); + if (dot > 0.99f) + { + // skip this test, we're not interested in testing + // the intractible cases + continue; + } + + // construct the lines + LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir; + LLLine first_line(first_point, some_point); + + LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir; + LLLine second_line(second_point, another_point); + + // compute the points of nearest approach + LLVector3 some_computed_point = first_line.nearestApproach(second_line); + LLVector3 another_computed_point = second_line.nearestApproach(first_line); + + // compute the error + F32 first_error = (some_point - some_computed_point).length(); + F32 scale = llmax((some_point - another_point).length(), some_point.length()); + scale = llmax(scale, another_point.length()); + scale = llmax(scale, 1.f); + F32 first_relative_error = first_error / scale; + + F32 second_error = (another_point - another_computed_point).length(); + F32 second_relative_error = second_error / scale; + + //if (first_relative_error > allowable_relative_error) + //{ + // std::cout << "first_error = " << first_error + // << " first_relative_error = " << first_relative_error + // << " scale = " << scale + // << " dir_dot = " << (first_dir * second_dir) + // << std::endl; + //} + //if (second_relative_error > allowable_relative_error) + //{ + // std::cout << "second_error = " << second_error + // << " second_relative_error = " << second_relative_error + // << " scale = " << scale + // << " dist = " << (some_point - another_point).length() + // << " dir_dot = " << (first_dir * second_dir) + // << std::endl; + //} + + // test that the errors are small + + ensure("first line should accurately compute its closest approach", + first_relative_error <= allowable_relative_error); + ensure("second line should accurately compute its closest approach", + second_relative_error <= allowable_relative_error); + } */ - } - - F32 ALMOST_PARALLEL = 0.99f; - template<> template<> - void line_object::test<3>() - { - // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method - - // first some known tests - LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f)); - LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f)); - LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f)); - - LLLine x_line; - LLLine y_line; - LLLine z_line; - - bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane); - bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane); - bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane); - - ensure("xy and zx planes should intersect", x_success); - ensure("yz and xy planes should intersect", y_success); - ensure("zx and yz planes should intersect", z_success); - - LLVector3 direction = x_line.getDirection(); - ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f - && 0.f == direction.mV[VY] - && 0.f == direction.mV[VZ] ); - direction = y_line.getDirection(); - ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] - && fabs(direction.mV[VY]) == 1.f - && 0.f == direction.mV[VZ] ); - direction = z_line.getDirection(); - ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] - && 0.f == direction.mV[VY] - && fabs(direction.mV[VZ]) == 1.f ); - - // next some random tests - F32 allowable_relative_error = 0.0001f; - S32 number_of_tests = 20; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate the known line - LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - some_point.normalize(); - some_point *= ll_frand(LARGE_RADIUS); - LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - another_point.normalize(); - another_point *= ll_frand(LARGE_RADIUS); - LLLine known_intersection(some_point, another_point); - - // compute a plane that intersect the line - LLVector3 point_on_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_plane.normalize(); - point_on_plane *= ll_frand(LARGE_RADIUS); - LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); - plane_normal.normalize(); - LLLine first_plane(point_on_plane, point_on_plane + plane_normal); - - // compute a different plane that intersect the line - LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_different_plane.normalize(); - point_on_different_plane *= ll_frand(LARGE_RADIUS); - LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); - different_plane_normal.normalize(); - LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal); - - if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL) - { - // the two planes are approximately parallel, so we won't test this case - continue; - } - - LLLine measured_intersection; - bool success = LLLine::getIntersectionBetweenTwoPlanes( - measured_intersection, - first_plane, - second_plane); - - try - { - ensure("plane intersection should succeed", success); - - F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); - ensure("measured intersection should be parallel to known intersection", - dot > ALMOST_PARALLEL); - - ensure("measured intersection should pass near known point", - measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); - } - catch (const failure&) - { - // If any of these assertions fail, since the values involved - // are randomly generated, unless we report them, we have no - // hope of diagnosing the problem. - LL_INFOS() << "some_point = " << some_point << '\n' - << "another_point = " << another_point << '\n' - << "known_intersection = " << known_intersection << '\n' - << "point_on_plane = " << point_on_plane << '\n' - << "plane_normal = " << plane_normal << '\n' - << "first_plane = " << first_plane << '\n' - << "point_on_different_plane = " << point_on_different_plane << '\n' - << "different_plane_normal = " << different_plane_normal << '\n' - << "second_plane = " << second_plane << '\n' - << "measured_intersection = " << measured_intersection << LL_ENDL; - throw; - } - } - } + } + + F32 ALMOST_PARALLEL = 0.99f; + template<> template<> + void line_object::test<3>() + { + // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method + + // first some known tests + LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f)); + LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f)); + LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f)); + + LLLine x_line; + LLLine y_line; + LLLine z_line; + + bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane); + bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane); + bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane); + + ensure("xy and zx planes should intersect", x_success); + ensure("yz and xy planes should intersect", y_success); + ensure("zx and yz planes should intersect", z_success); + + LLVector3 direction = x_line.getDirection(); + ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f + && 0.f == direction.mV[VY] + && 0.f == direction.mV[VZ] ); + direction = y_line.getDirection(); + ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] + && fabs(direction.mV[VY]) == 1.f + && 0.f == direction.mV[VZ] ); + direction = z_line.getDirection(); + ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] + && 0.f == direction.mV[VY] + && fabs(direction.mV[VZ]) == 1.f ); + + // next some random tests + F32 allowable_relative_error = 0.0001f; + S32 number_of_tests = 20; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate the known line + LLVector3 some_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + some_point.normalize(); + some_point *= ll_frand(LARGE_RADIUS); + LLVector3 another_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + another_point.normalize(); + another_point *= ll_frand(LARGE_RADIUS); + LLLine known_intersection(some_point, another_point); + + // compute a plane that intersect the line + LLVector3 point_on_plane( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_plane.normalize(); + point_on_plane *= ll_frand(LARGE_RADIUS); + LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); + plane_normal.normalize(); + LLLine first_plane(point_on_plane, point_on_plane + plane_normal); + + // compute a different plane that intersect the line + LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_different_plane.normalize(); + point_on_different_plane *= ll_frand(LARGE_RADIUS); + LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); + different_plane_normal.normalize(); + LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal); + + if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL) + { + // the two planes are approximately parallel, so we won't test this case + continue; + } + + LLLine measured_intersection; + bool success = LLLine::getIntersectionBetweenTwoPlanes( + measured_intersection, + first_plane, + second_plane); + + try + { + ensure("plane intersection should succeed", success); + + F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); + ensure("measured intersection should be parallel to known intersection", + dot > ALMOST_PARALLEL); + + ensure("measured intersection should pass near known point", + measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); + } + catch (const failure&) + { + // If any of these assertions fail, since the values involved + // are randomly generated, unless we report them, we have no + // hope of diagnosing the problem. + LL_INFOS() << "some_point = " << some_point << '\n' + << "another_point = " << another_point << '\n' + << "known_intersection = " << known_intersection << '\n' + << "point_on_plane = " << point_on_plane << '\n' + << "plane_normal = " << plane_normal << '\n' + << "first_plane = " << first_plane << '\n' + << "point_on_different_plane = " << point_on_different_plane << '\n' + << "different_plane_normal = " << different_plane_normal << '\n' + << "second_plane = " << second_plane << '\n' + << "measured_intersection = " << measured_intersection << LL_ENDL; + throw; + } + } + } } diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index c1c1db7437..1a32b8e62a 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -41,7 +41,7 @@ //========================================================================= // Map of pool sizes for known pools static const std::map DefaultPoolSizes{ - {std::string("Upload"), 1}, + {std::string("Upload"), 1}, {std::string("AIS"), 1}, // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. }; @@ -61,11 +61,11 @@ public: LLCoprocedurePool(const std::string &name, size_t size); ~LLCoprocedurePool(); - /// Places the coprocedure on the queue for processing. - /// + /// Places the coprocedure on the queue for processing. + /// /// @param name Is used for debugging and should identify this coroutine. - /// @param proc Is a bound function to be executed - /// + /// @param proc Is a bound function to be executed + /// /// @return This method returns a UUID that can be used later to cancel execution. LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc); @@ -91,7 +91,7 @@ public: } void close(); - + private: struct QueuedCoproc { @@ -108,7 +108,7 @@ private: CoProcedure_t mProc; }; - // we use a buffered_channel here rather than unbuffered_channel since we want to be able to + // we use a buffered_channel here rather than unbuffered_channel since we want to be able to // push values without blocking,even if there's currently no one calling a pop operation (due to // fiber running right now) typedef boost::fibers::buffered_channel CoprocQueue_t; @@ -167,7 +167,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) if (size == 0) { - // if not found grab the know default... if there is no known + // if not found grab the know default... if there is no known // default use a reasonable number like 5. auto it = DefaultPoolSizes.find(poolName); size = (it != DefaultPoolSizes.end()) ? it->second : DEFAULT_POOL_SIZE; @@ -190,7 +190,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) //------------------------------------------------------------------------- LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc) { - // Attempt to find the pool and enqueue the procedure. If the pool does + // Attempt to find the pool and enqueue the procedure. If the pool does // not exist, create it. poolMap_t::iterator it = mPoolMap.find(pool); @@ -350,7 +350,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; } -LLCoprocedurePool::~LLCoprocedurePool() +LLCoprocedurePool::~LLCoprocedurePool() { } diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 4a5b220008..2711e8088d 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -28,71 +28,71 @@ #include "llui.h" LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) -: LLEventTimer(period), - mCallback(cb), - mCurrentTickCount(0), - mIsFlashingInProgress(false), - mIsCurrentlyHighlighted(false), - mUnset(false) +: LLEventTimer(period), + mCallback(cb), + mCurrentTickCount(0), + mIsFlashingInProgress(false), + mIsCurrentlyHighlighted(false), + mUnset(false) { - stop(); + stop(); - // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. - // Due to Timer is implemented as derived class from EventTimer it is impossible to change period - // in runtime. So, both settings are made as required restart. - mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); - if (mPeriod <= 0) - { - mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); - } + // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. + // Due to Timer is implemented as derived class from EventTimer it is impossible to change period + // in runtime. So, both settings are made as required restart. + mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); + if (mPeriod <= 0) + { + mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); + } } void LLFlashTimer::unset() { - mUnset = true; - mCallback = NULL; + mUnset = true; + mCallback = NULL; } bool LLFlashTimer::tick() { - mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; + mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; - if (mCallback) - { - mCallback(mIsCurrentlyHighlighted); - } + if (mCallback) + { + mCallback(mIsCurrentlyHighlighted); + } - if (++mCurrentTickCount >= mFlashCount) - { - stopFlashing(); - } + if (++mCurrentTickCount >= mFlashCount) + { + stopFlashing(); + } - return mUnset; + return mUnset; } void LLFlashTimer::startFlashing() { - mIsFlashingInProgress = true; - mIsCurrentlyHighlighted = true; - start(); + mIsFlashingInProgress = true; + mIsCurrentlyHighlighted = true; + start(); } void LLFlashTimer::stopFlashing() { - stop(); - mIsFlashingInProgress = false; - mIsCurrentlyHighlighted = false; - mCurrentTickCount = 0; + stop(); + mIsFlashingInProgress = false; + mIsCurrentlyHighlighted = false; + mCurrentTickCount = 0; } bool LLFlashTimer::isFlashingInProgress() { - return mIsFlashingInProgress; + return mIsFlashingInProgress; } bool LLFlashTimer::isCurrentlyHighlighted() { - return mIsCurrentlyHighlighted; + return mIsCurrentlyHighlighted; } diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index 4a2088734d..988b577ed2 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -34,41 +34,41 @@ class LLFlashTimer : public LLEventTimer { public: - typedef boost::function callback_t; + typedef boost::function callback_t; - /** - * Constructor. - * - * @param count - how many times callback should be called (twice to not change original state) - * @param period - how frequently callback should be called - * @param cb - callback to be called each tick - */ - LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); - ~LLFlashTimer() {}; + /** + * Constructor. + * + * @param count - how many times callback should be called (twice to not change original state) + * @param period - how frequently callback should be called + * @param cb - callback to be called each tick + */ + LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); + ~LLFlashTimer() {}; - bool tick() override; + bool tick() override; - void startFlashing(); - void stopFlashing(); + void startFlashing(); + void stopFlashing(); - bool isFlashingInProgress(); - bool isCurrentlyHighlighted(); - /* - * Use this instead of deleting this object. - * The next call to tick() will return true and that will destroy this object. - */ - void unset(); + bool isFlashingInProgress(); + bool isCurrentlyHighlighted(); + /* + * Use this instead of deleting this object. + * The next call to tick() will return true and that will destroy this object. + */ + void unset(); private: - callback_t mCallback; - /** - * How many times parent will blink. - */ - S32 mFlashCount; - S32 mCurrentTickCount; - bool mIsCurrentlyHighlighted; - bool mIsFlashingInProgress; - bool mUnset; + callback_t mCallback; + /** + * How many times parent will blink. + */ + S32 mFlashCount; + S32 mCurrentTickCount; + bool mIsCurrentlyHighlighted; + bool mIsFlashingInProgress; + bool mUnset; }; #endif /* LL_FLASHTIMER_H */ diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index fdbfb38474..e8d6043e54 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -1,25 +1,25 @@ -/** +/** * @file llmenugl.h * @brief Declaration of the opengl based menu system. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,183 +45,183 @@ extern S32 MENU_BAR_WIDTH; class LLMenuKeyboardBinding { public: - KEY mKey; - MASK mMask; + KEY mKey; + MASK mMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // -// The LLMenuItemGL represents a single menu item in a menu. +// The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl { public: - struct Params : public LLInitParam::Block - { - Optional shortcut; - Optional jump_key; - Optional use_mac_ctrl, - allow_key_repeat; - - Ignored rect, - left, - top, - right, - bottom, - width, - height, - bottom_delta, - left_delta; - - Optional enabled_color, - disabled_color, - highlight_bg_color, - highlight_fg_color; - - - Params(); - }; + struct Params : public LLInitParam::Block + { + Optional shortcut; + Optional jump_key; + Optional use_mac_ctrl, + allow_key_repeat; + + Ignored rect, + left, + top, + right, + bottom, + width, + height, + bottom_delta, + left_delta; + + Optional enabled_color, + disabled_color, + highlight_bg_color, + highlight_fg_color; + + + Params(); + }; protected: - LLMenuItemGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemGL(const Params&); + friend class LLUICtrlFactory; public: - // LLView overrides - /*virtual*/ void onVisibilityChange(BOOL new_visibility); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - - // LLUICtrl overrides - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ LLSD getValue() const; - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } - - void setJumpKey(KEY key); - KEY getJumpKey() const { return mJumpKey; } - - // set the font used by this item. - void setFont(const LLFontGL* font) { mFont = font; } - const LLFontGL* getFont() const { return mFont; } - - // returns the height in pixels for the current font. - virtual U32 getNominalHeight( void ) const; - - // Marks item as not needing space for check marks or accelerator keys - virtual void setBriefItem(BOOL brief); - virtual BOOL isBriefItem() const; - - virtual BOOL addToAcceleratorList(std::list *listp); - void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } - BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } - - // change the label - void setLabel( const LLStringExplicit& label ) { mLabel = label; } - std::string getLabel( void ) const { return mLabel.getString(); } - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - - // Get the parent menu for this item - virtual class LLMenuGL* getMenu() const; - - // returns the normal width of this control in pixels - this is - // used for calculating the widest item, as well as for horizontal - // arrangement. - virtual U32 getNominalWidth( void ) const; - - // buildDrawLabel() - constructs the string used during the draw() - // function. This reduces the overall string manipulation, but can - // lead to visual errors if the state of the object changes - // without the knowledge of the menu item. For example, if a - // boolean being watched is changed outside of the menu item's - // onCommit() function, the draw buffer will not be updated and will - // reflect the wrong value. If this ever becomes an issue, there - // are ways to fix this. - // Returns the enabled state of the item. - virtual void buildDrawLabel( void ); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateBranchParent( LLView* parentp ){}; - - virtual void onCommit( void ); - - virtual void setHighlight( BOOL highlight ); - virtual BOOL getHighlight() const { return mHighlight; } - - // determine if this represents an active sub-menu - virtual BOOL isActive( void ) const { return FALSE; } - - // determine if this represents an open sub-menu - virtual BOOL isOpen( void ) const { return FALSE; } - - virtual void setEnabledSubMenus(BOOL enable){}; - - // LLView Functionality - virtual BOOL handleKeyHere( KEY key, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - - virtual void draw( void ); - - BOOL getHover() const { return mGotHover; } - - void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } - BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } + // LLView overrides + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + + // LLUICtrl overrides + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } + + void setJumpKey(KEY key); + KEY getJumpKey() const { return mJumpKey; } + + // set the font used by this item. + void setFont(const LLFontGL* font) { mFont = font; } + const LLFontGL* getFont() const { return mFont; } + + // returns the height in pixels for the current font. + virtual U32 getNominalHeight( void ) const; + + // Marks item as not needing space for check marks or accelerator keys + virtual void setBriefItem(BOOL brief); + virtual BOOL isBriefItem() const; + + virtual BOOL addToAcceleratorList(std::list *listp); + void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } + BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } + + // change the label + void setLabel( const LLStringExplicit& label ) { mLabel = label; } + std::string getLabel( void ) const { return mLabel.getString(); } + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + + // Get the parent menu for this item + virtual class LLMenuGL* getMenu() const; + + // returns the normal width of this control in pixels - this is + // used for calculating the widest item, as well as for horizontal + // arrangement. + virtual U32 getNominalWidth( void ) const; + + // buildDrawLabel() - constructs the string used during the draw() + // function. This reduces the overall string manipulation, but can + // lead to visual errors if the state of the object changes + // without the knowledge of the menu item. For example, if a + // boolean being watched is changed outside of the menu item's + // onCommit() function, the draw buffer will not be updated and will + // reflect the wrong value. If this ever becomes an issue, there + // are ways to fix this. + // Returns the enabled state of the item. + virtual void buildDrawLabel( void ); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateBranchParent( LLView* parentp ){}; + + virtual void onCommit( void ); + + virtual void setHighlight( BOOL highlight ); + virtual BOOL getHighlight() const { return mHighlight; } + + // determine if this represents an active sub-menu + virtual BOOL isActive( void ) const { return FALSE; } + + // determine if this represents an open sub-menu + virtual BOOL isOpen( void ) const { return FALSE; } + + virtual void setEnabledSubMenus(BOOL enable){}; + + // LLView Functionality + virtual BOOL handleKeyHere( KEY key, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + virtual void draw( void ); + + BOOL getHover() const { return mGotHover; } + + void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } + BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } protected: - void setHover(BOOL hover) { mGotHover = hover; } + void setHover(BOOL hover) { mGotHover = hover; } - // This function appends the character string representation of - // the current accelerator key and mask to the provided string. - void appendAcceleratorString( std::string& st ) const; + // This function appends the character string representation of + // the current accelerator key and mask to the provided string. + void appendAcceleratorString( std::string& st ) const; - virtual std::string _getSearchText() const - { - return mLabel.getString(); - } + virtual std::string _getSearchText() const + { + return mLabel.getString(); + } protected: - KEY mAcceleratorKey; - MASK mAcceleratorMask; - // mLabel contains the actual label specified by the user. - LLUIString mLabel; - - // The draw labels contain some of the labels that we draw during - // the draw() routine. This optimizes away some of the string - // manipulation. - LLUIString mDrawBoolLabel; - LLUIString mDrawAccelLabel; - LLUIString mDrawBranchLabel; - - LLUIColor mEnabledColor; - LLUIColor mDisabledColor; - LLUIColor mHighlightBackground; - LLUIColor mHighlightForeground; - - BOOL mHighlight; + KEY mAcceleratorKey; + MASK mAcceleratorMask; + // mLabel contains the actual label specified by the user. + LLUIString mLabel; + + // The draw labels contain some of the labels that we draw during + // the draw() routine. This optimizes away some of the string + // manipulation. + LLUIString mDrawBoolLabel; + LLUIString mDrawAccelLabel; + LLUIString mDrawBranchLabel; + + LLUIColor mEnabledColor; + LLUIColor mDisabledColor; + LLUIColor mHighlightBackground; + LLUIColor mHighlightForeground; + + BOOL mHighlight; private: - // Keyboard and mouse variables - BOOL mAllowKeyRepeat; - BOOL mGotHover; + // Keyboard and mouse variables + BOOL mAllowKeyRepeat; + BOOL mGotHover; - // If true, suppress normal space for check marks on the left and accelerator - // keys on the right. - BOOL mBriefItem; + // If true, suppress normal space for check marks on the left and accelerator + // keys on the right. + BOOL mBriefItem; - // Font for this item - const LLFontGL* mFont; - BOOL mDrawTextDisabled; + // Font for this item + const LLFontGL* mFont; + BOOL mDrawTextDisabled; - KEY mJumpKey; + KEY mJumpKey; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,22 +232,22 @@ private: class LLMenuItemSeparatorGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { + struct Params : public LLInitParam::Block + { Optional on_visible; Params(); - }; + }; LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params()); - /*virtual*/ void draw( void ); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void draw( void ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); virtual void buildDrawLabel(); - /*virtual*/ U32 getNominalHeight( void ) const; + /*virtual*/ U32 getNominalHeight( void ) const; private: enable_signal_t mVisibleSignal; @@ -263,49 +263,49 @@ private: class LLMenuItemCallGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Optional on_enable; - Optional on_click; - Optional on_visible; - Params() - : on_enable("on_enable"), - on_click("on_click"), - on_visible("on_visible") - {} - }; + struct Params : public LLInitParam::Block + { + Optional on_enable; + Optional on_click; + Optional on_visible; + Params() + : on_enable("on_enable"), + on_click("on_click"), + on_visible("on_visible") + {} + }; protected: - LLMenuItemCallGL(const Params&); - friend class LLUICtrlFactory; - void updateEnabled( void ); - void updateVisible( void ); + LLMenuItemCallGL(const Params&); + friend class LLUICtrlFactory; + void updateEnabled( void ); + void updateVisible( void ); public: - void initFromParams(const Params& p); - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - virtual void onCommit( void ); - - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - //virtual void draw(); - - boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) - { - return setCommitCallback(cb); - } - - boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) - { - return mEnableSignal.connect(cb); - } - + void initFromParams(const Params& p); + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + virtual void onCommit( void ); + + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + //virtual void draw(); + + boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) + { + return setCommitCallback(cb); + } + + boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) + { + return mEnableSignal.connect(cb); + } + private: - enable_signal_t mEnableSignal; - enable_signal_t mVisibleSignal; + enable_signal_t mEnableSignal; + enable_signal_t mVisibleSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -318,40 +318,40 @@ private: // EFFICIENT because it may need to be checked a lot. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemCheckGL -: public LLMenuItemCallGL +class LLMenuItemCheckGL +: public LLMenuItemCallGL { public: - struct Params : public LLInitParam::Block - { - Optional on_check; - Params() - : on_check("on_check") - {} - }; + struct Params : public LLInitParam::Block + { + Optional on_check; + Params() + : on_check("on_check") + {} + }; protected: - LLMenuItemCheckGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemCheckGL(const Params&); + friend class LLUICtrlFactory; public: - - void initFromParams(const Params& p); - - virtual void onCommit( void ); - - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) - { - return mCheckSignal.connect(cb); - } - + + void initFromParams(const Params& p); + + virtual void onCommit( void ); + + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) + { + return mCheckSignal.connect(cb); + } + private: - enable_signal_t mCheckSignal; + enable_signal_t mCheckSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -368,199 +368,199 @@ private: // child widget registry struct MenuRegistry : public LLChildRegistry { - LLSINGLETON_EMPTY_CTOR(MenuRegistry); + LLSINGLETON_EMPTY_CTOR(MenuRegistry); }; -class LLMenuGL -: public LLUICtrl +class LLMenuGL +: public LLUICtrl { public: - struct Params : public LLInitParam::Block - { - Optional jump_key; - Optional horizontal_layout, - can_tear_off, - drop_shadow, - bg_visible, - create_jump_keys, - keep_fixed_size, - scrollable; - Optional max_scrollable_items; - Optional preferred_width; - Optional bg_color; - Optional shortcut_pad; - - Params() - : jump_key("jump_key", KEY_NONE), - horizontal_layout("horizontal_layout"), - can_tear_off("tear_off", false), - drop_shadow("drop_shadow", true), - bg_visible("bg_visible", true), - create_jump_keys("create_jump_keys", false), - keep_fixed_size("keep_fixed_size", false), - bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), - scrollable("scrollable", false), - max_scrollable_items("max_scrollable_items", U32_MAX), - preferred_width("preferred_width", U32_MAX), - shortcut_pad("shortcut_pad") - { - addSynonym(bg_visible, "opaque"); - addSynonym(bg_color, "color"); - addSynonym(can_tear_off, "can_tear_off"); - } - }; - - // my valid children are contained in MenuRegistry - typedef MenuRegistry child_registry_t; - - void initFromParams(const Params&); - - // textual artwork which menugl-imitators may want to match - static const std::string BOOLEAN_TRUE_PREFIX; - static const std::string BRANCH_SUFFIX; - static const std::string ARROW_UP; - static const std::string ARROW_DOWN; - - // for scrollable menus - typedef enum e_scrolling_direction - { - SD_UP = 0, - SD_DOWN = 1, - SD_BEGIN = 2, - SD_END = 3 - } EScrollingDirection; + struct Params : public LLInitParam::Block + { + Optional jump_key; + Optional horizontal_layout, + can_tear_off, + drop_shadow, + bg_visible, + create_jump_keys, + keep_fixed_size, + scrollable; + Optional max_scrollable_items; + Optional preferred_width; + Optional bg_color; + Optional shortcut_pad; + + Params() + : jump_key("jump_key", KEY_NONE), + horizontal_layout("horizontal_layout"), + can_tear_off("tear_off", false), + drop_shadow("drop_shadow", true), + bg_visible("bg_visible", true), + create_jump_keys("create_jump_keys", false), + keep_fixed_size("keep_fixed_size", false), + bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), + scrollable("scrollable", false), + max_scrollable_items("max_scrollable_items", U32_MAX), + preferred_width("preferred_width", U32_MAX), + shortcut_pad("shortcut_pad") + { + addSynonym(bg_visible, "opaque"); + addSynonym(bg_color, "color"); + addSynonym(can_tear_off, "can_tear_off"); + } + }; + + // my valid children are contained in MenuRegistry + typedef MenuRegistry child_registry_t; + + void initFromParams(const Params&); + + // textual artwork which menugl-imitators may want to match + static const std::string BOOLEAN_TRUE_PREFIX; + static const std::string BRANCH_SUFFIX; + static const std::string ARROW_UP; + static const std::string ARROW_DOWN; + + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; protected: - LLMenuGL(const LLMenuGL::Params& p); - friend class LLUICtrlFactory; - // let branching menu items use my protected traversal methods - friend class LLMenuItemBranchGL; + LLMenuGL(const LLMenuGL::Params& p); + friend class LLUICtrlFactory; + // let branching menu items use my protected traversal methods + friend class LLMenuItemBranchGL; public: - virtual ~LLMenuGL( void ); - - void parseChildXML(LLXMLNodePtr child, LLView* parent); - - // LLView Functionality - /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - /*virtual*/ void draw( void ); - /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + virtual ~LLMenuGL( void ); + + void parseChildXML(LLXMLNodePtr child, LLView* parent); + + // LLView Functionality + /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + /*virtual*/ void draw( void ); + /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void deleteAllChildren(); - /*virtual*/ void removeChild( LLView* ctrl); - /*virtual*/ BOOL postBuild(); - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; - - BOOL clearHoverItem(); - - // return the name label - const std::string& getLabel( void ) const { return mLabel.getString(); } - void setLabel(const LLStringExplicit& label) { mLabel = label; } - - // background colors - void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } - const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } - void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - void setCanTearOff(BOOL tear_off); - - // add a separator to this menu - virtual BOOL addSeparator(); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateParent( LLView* parentp ); - - // setItemEnabled() - pass the name and the enable flag for a - // menu item. TRUE will make sure it's enabled, FALSE will disable - // it. - void setItemEnabled( const std::string& name, BOOL enable ); - - // propagate message to submenus - void setEnabledSubMenus(BOOL enable); - - void setItemVisible( const std::string& name, BOOL visible); + /*virtual*/ void removeChild( LLView* ctrl); + /*virtual*/ BOOL postBuild(); + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; + + BOOL clearHoverItem(); + + // return the name label + const std::string& getLabel( void ) const { return mLabel.getString(); } + void setLabel(const LLStringExplicit& label) { mLabel = label; } + + // background colors + void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } + const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } + void setBackgroundVisible( BOOL b ) { mBgVisible = b; } + void setCanTearOff(BOOL tear_off); + + // add a separator to this menu + virtual BOOL addSeparator(); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateParent( LLView* parentp ); + + // setItemEnabled() - pass the name and the enable flag for a + // menu item. TRUE will make sure it's enabled, FALSE will disable + // it. + void setItemEnabled( const std::string& name, BOOL enable ); + + // propagate message to submenus + void setEnabledSubMenus(BOOL enable); + + void setItemVisible( const std::string& name, BOOL visible); void setItemLabel(const std::string &name, const std::string &label); - - // sets the left,bottom corner of menu, useful for popups - void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL handleJumpKey(KEY key); + // sets the left,bottom corner of menu, useful for popups + void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL jumpKeysActive(); + virtual BOOL handleJumpKey(KEY key); - virtual BOOL isOpen(); + virtual BOOL jumpKeysActive(); - void needsArrange() { mNeedsArrange = TRUE; } - // Shape this menu to fit the current state of the children, and - // adjust the child rects to fit. This is called automatically - // when you add items. *FIX: We may need to deal with visibility - // arrangement. - virtual void arrange( void ); - void arrangeAndClear( void ); + virtual BOOL isOpen(); - // remove all items on the menu - void empty( void ); + void needsArrange() { mNeedsArrange = TRUE; } + // Shape this menu to fit the current state of the children, and + // adjust the child rects to fit. This is called automatically + // when you add items. *FIX: We may need to deal with visibility + // arrangement. + virtual void arrange( void ); + void arrangeAndClear( void ); - // erase group of items from menu - void erase( S32 begin, S32 end, bool arrange = true ); + // remove all items on the menu + void empty( void ); - // add new item at position - void insert( S32 begin, LLView * ctrl, bool arrange = true ); + // erase group of items from menu + void erase( S32 begin, S32 end, bool arrange = true ); - void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items - LLMenuItemGL* getItem(S32 number); // 0 = first item + // add new item at position + void insert( S32 begin, LLView * ctrl, bool arrange = true ); + + void setItemLastSelected(LLMenuItemGL* item); // must be in menu + U32 getItemCount(); // number of menu items + LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getItem(std::string name); - LLMenuItemGL* getHighlightedItem(); + LLMenuItemGL* getHighlightedItem(); + + LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + void buildDrawLabels(); + void createJumpKeys(); - void buildDrawLabels(); - void createJumpKeys(); + // Show popup at a specific location, in the spawn_view's coordinate frame + static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); - // Show popup at a specific location, in the spawn_view's coordinate frame - static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); + // Whether to drop shadow menu bar + void setDropShadowed( const BOOL shadowed ); - // Whether to drop shadow menu bar - void setDropShadowed( const BOOL shadowed ); + void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } + LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } - void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } - LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } + void setTornOff(BOOL torn_off); + BOOL getTornOff() { return mTornOff; } - void setTornOff(BOOL torn_off); - BOOL getTornOff() { return mTornOff; } + BOOL getCanTearOff() { return mTearOffItem != NULL; } - BOOL getCanTearOff() { return mTearOffItem != NULL; } + KEY getJumpKey() const { return mJumpKey; } + void setJumpKey(KEY key) { mJumpKey = key; } - KEY getJumpKey() const { return mJumpKey; } - void setJumpKey(KEY key) { mJumpKey = key; } + static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } + static BOOL getKeyboardMode() { return sKeyboardMode; } - static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } - static BOOL getKeyboardMode() { return sKeyboardMode; } + S32 getShortcutPad() { return mShortcutPad; } - S32 getShortcutPad() { return mShortcutPad; } + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } - bool scrollItems(EScrollingDirection direction); - BOOL isScrollable() const { return mScrollable; } + static class LLMenuHolderGL* sMenuContainer; - static class LLMenuHolderGL* sMenuContainer; - - void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } - bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } - void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } - BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } + void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } + BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } - // add a context menu branch - BOOL appendContextSubMenu(LLMenuGL *menu); + // add a context menu branch + BOOL appendContextSubMenu(LLMenuGL *menu); // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); @@ -571,31 +571,31 @@ public: const LLFontGL *getFont() const { return mFont; } protected: - void createSpilloverBranch(); - void cleanupSpilloverBranch(); - - // Used in LLContextMenu and in LLTogleableMenu - // to add an item of context menu branch - bool addContextChild(LLView* view, S32 tab_group); - - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; - item_list_t mItems; - LLMenuItemGL*mFirstVisibleItem; - LLMenuItemGL *mArrowUpItem, *mArrowDownItem; - - typedef std::map navigation_key_map_t; - navigation_key_map_t mJumpKeys; - S32 mLastMouseX; - S32 mLastMouseY; - S32 mMouseVelX; - S32 mMouseVelY; - U32 mMaxScrollableItems; - U32 mPreferredWidth; - BOOL mHorizontalLayout; - BOOL mScrollable; - BOOL mKeepFixedSize; - BOOL mNeedsArrange; + void createSpilloverBranch(); + void cleanupSpilloverBranch(); + + // Used in LLContextMenu and in LLTogleableMenu + // to add an item of context menu branch + bool addContextChild(LLView* view, S32 tab_group); + + // TODO: create accessor methods for these? + typedef std::list< LLMenuItemGL* > item_list_t; + item_list_t mItems; + LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; + + typedef std::map navigation_key_map_t; + navigation_key_map_t mJumpKeys; + S32 mLastMouseX; + S32 mLastMouseY; + S32 mMouseVelX; + S32 mMouseVelY; + U32 mMaxScrollableItems; + U32 mPreferredWidth; + BOOL mHorizontalLayout; + BOOL mScrollable; + BOOL mKeepFixedSize; + BOOL mNeedsArrange; // Font for top menu items only const LLFontGL* mFont; @@ -603,27 +603,27 @@ protected: private: - static LLColor4 sDefaultBackgroundColor; - static BOOL sKeyboardMode; - - BOOL mAlwaysShowMenu; - - LLUIColor mBackgroundColor; - BOOL mBgVisible; - LLHandle mParentMenuItem; - LLUIString mLabel; - BOOL mDropShadowed; // Whether to drop shadow - bool mHasSelection; - LLFrameTimer mFadeTimer; - LLTimer mScrollItemsTimer; - BOOL mTornOff; - class LLMenuItemTearOffGL* mTearOffItem; - class LLMenuItemBranchGL* mSpilloverBranch; - LLMenuGL* mSpilloverMenu; - KEY mJumpKey; - BOOL mCreateJumpKeys; - S32 mShortcutPad; - bool mResetScrollPositionOnShow; + static LLColor4 sDefaultBackgroundColor; + static BOOL sKeyboardMode; + + BOOL mAlwaysShowMenu; + + LLUIColor mBackgroundColor; + BOOL mBgVisible; + LLHandle mParentMenuItem; + LLUIString mLabel; + BOOL mDropShadowed; // Whether to drop shadow + bool mHasSelection; + LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; + BOOL mTornOff; + class LLMenuItemTearOffGL* mTearOffItem; + class LLMenuItemBranchGL* mSpilloverBranch; + LLMenuGL* mSpilloverMenu; + KEY mJumpKey; + BOOL mCreateJumpKeys; + S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL @@ -638,61 +638,61 @@ private: class LLMenuItemBranchGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Optional branch; - }; + struct Params : public LLInitParam::Block + { + Optional branch; + }; protected: - LLMenuItemBranchGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemBranchGL(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMenuItemBranchGL(); - - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual ~LLMenuItemBranchGL(); - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list *listp); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // check if we've used these accelerators already + virtual BOOL addToAcceleratorList(std::list *listp); - virtual void onCommit( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual void onCommit( void ); - // set the hover status (called by it's menu) and if the object is - // active. This is used for behavior transfer. - virtual void setHighlight( BOOL highlight ); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); + // set the hover status (called by it's menu) and if the object is + // active. This is used for behavior transfer. + virtual void setHighlight( BOOL highlight ); - virtual BOOL isActive() const; + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL isOpen() const; + virtual BOOL isActive() const; - LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } + virtual BOOL isOpen() const; - virtual void updateBranchParent( LLView* parentp ); + LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } - // LLView Functionality - virtual void onVisibilityChange( BOOL curVisibilityIn ); + virtual void updateBranchParent( LLView* parentp ); - virtual void draw(); + // LLView Functionality + virtual void onVisibilityChange( BOOL curVisibilityIn ); - virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } + virtual void draw(); - virtual void openMenu(); + virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } - virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual void openMenu(); + + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; private: - LLHandle mBranchHandle; + LLHandle mBranchHandle; }; // end class LLMenuItemBranchGL @@ -705,44 +705,44 @@ class LLContextMenu : public LLMenuGL { public: - struct Params : public LLInitParam::Block - { - Params() - { - changeDefault(visible, false); - } - }; + struct Params : public LLInitParam::Block + { + Params() + { + changeDefault(visible, false); + } + }; protected: - LLContextMenu(const Params& p); - friend class LLUICtrlFactory; + LLContextMenu(const Params& p); + friend class LLUICtrlFactory; public: - virtual ~LLContextMenu() {} + virtual ~LLContextMenu() {} + + // LLView Functionality + // can't set visibility directly, must call show or hide + virtual void setVisible (BOOL visible); - // LLView Functionality - // can't set visibility directly, must call show or hide - virtual void setVisible (BOOL visible); - - virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); - virtual void hide (); + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); + virtual void hide (); - virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); - virtual bool addChild (LLView* view, S32 tab_group = 0); + virtual bool addChild (LLView* view, S32 tab_group = 0); - LLHandle getHandle() { return getDerivedHandle(); } + LLHandle getHandle() { return getDerivedHandle(); } - LLView* getSpawningView() const { return mSpawningViewHandle.get(); } - void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } protected: - BOOL mHoveredAnyItem; - LLMenuItemGL* mHoverItem; - LLRootHandle mHandle; - LLHandle mSpawningViewHandle; + BOOL mHoveredAnyItem; + LLMenuItemGL* mHoverItem; + LLRootHandle mHandle; + LLHandle mSpawningViewHandle; }; //----------------------------------------------------------------------------- @@ -752,28 +752,28 @@ protected: class LLContextMenuBranch : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Mandatory branch; - }; + struct Params : public LLInitParam::Block + { + Mandatory branch; + }; - LLContextMenuBranch(const Params&); + LLContextMenuBranch(const Params&); - virtual ~LLContextMenuBranch(); + virtual ~LLContextMenuBranch(); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - // onCommit() - do the primary funcationality of the menu item. - virtual void onCommit( void ); + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); - LLContextMenu* getBranch() { return mBranch.get(); } - void setHighlight( BOOL highlight ); + LLContextMenu* getBranch() { return mBranch.get(); } + void setHighlight( BOOL highlight ); protected: - void showSubMenu(); + void showSubMenu(); - LLHandle mBranch; + LLHandle mBranch; }; @@ -786,43 +786,43 @@ protected: class LLMenuBarGL : public LLMenuGL { public: - struct Params : public LLInitParam::Block - {}; - LLMenuBarGL( const Params& p ); - virtual ~LLMenuBarGL(); + struct Params : public LLInitParam::Block + {}; + LLMenuBarGL( const Params& p ); + virtual ~LLMenuBarGL(); - /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleJumpKey(KEY key); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleJumpKey(KEY key); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ BOOL jumpKeysActive(); + /*virtual*/ void draw(); + /*virtual*/ BOOL jumpKeysActive(); - // add a vertical separator to this menu - virtual BOOL addSeparator(); + // add a vertical separator to this menu + virtual BOOL addSeparator(); - // LLView Functionality - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + // LLView Functionality + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - // Returns x position of rightmost child, usually Help menu - S32 getRightmostMenuEdge(); + // Returns x position of rightmost child, usually Help menu + S32 getRightmostMenuEdge(); - void resetMenuTrigger() { mAltKeyTrigger = FALSE; } + void resetMenuTrigger() { mAltKeyTrigger = FALSE; } // add a menu - this will create a drop down menu. virtual BOOL appendMenu(LLMenuGL *menu); private: - // rearrange the child rects so they fit the shape of the menu - // bar. - virtual void arrange( void ); + // rearrange the child rects so they fit the shape of the menu + // bar. + virtual void arrange( void ); - void checkMenuTrigger(); + void checkMenuTrigger(); - std::list mAccelerators; - BOOL mAltKeyTrigger; + std::list mAccelerators; + BOOL mAltKeyTrigger; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -833,39 +833,39 @@ private: class LLMenuHolderGL : public LLPanel { public: - struct Params : public LLInitParam::Block - {}; - LLMenuHolderGL(const Params& p); - virtual ~LLMenuHolderGL() {} + struct Params : public LLInitParam::Block + {}; + LLMenuHolderGL(const Params& p); + virtual ~LLMenuHolderGL() {} - virtual BOOL hideMenus(); - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - void setCanHide(BOOL can_hide) { mCanHide = can_hide; } + virtual BOOL hideMenus(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + void setCanHide(BOOL can_hide) { mCanHide = can_hide; } - // LLView functionality - virtual void draw(); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + // LLView functionality + virtual void draw(); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - // Close context menus on right mouse up not handled by menus. - /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + // Close context menus on right mouse up not handled by menus. + /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual const LLRect getMenuRect() const { return getLocalRect(); } - LLView*const getVisibleMenu() const; - virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual const LLRect getMenuRect() const { return getLocalRect(); } + LLView*const getVisibleMenu() const; + virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} - static void setActivatedItem(LLMenuItemGL* item); + static void setActivatedItem(LLMenuItemGL* item); - // Need to detect if mouse-up after context menu spawn has moved. - // If not, need to keep the menu up. - static LLCoordGL sContextMenuSpawnPos; + // Need to detect if mouse-up after context menu spawn has moved. + // If not, need to keep the menu up. + static LLCoordGL sContextMenuSpawnPos; private: - static LLHandle sItemLastSelectedHandle; - static LLFrameTimer sItemActivationTimer; + static LLHandle sItemLastSelectedHandle; + static LLFrameTimer sItemActivationTimer; - BOOL mCanHide; + BOOL mCanHide; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -877,26 +877,26 @@ private: class LLTearOffMenu : public LLFloater { public: - static LLTearOffMenu* create(LLMenuGL* menup); - virtual ~LLTearOffMenu(); + static LLTearOffMenu* create(LLMenuGL* menup); + virtual ~LLTearOffMenu(); - virtual void draw(void); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual void translate(S32 x, S32 y); + virtual void draw(void); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual void translate(S32 x, S32 y); - void updateSize(); + void updateSize(); private: - LLTearOffMenu(LLMenuGL* menup); - - void closeTearOff(); - - LLView* mOldParent; - LLMenuGL* mMenu; - S32 mTargetHeight; + LLTearOffMenu(LLMenuGL* menup); + + void closeTearOff(); + + LLView* mOldParent; + LLMenuGL* mMenu; + S32 mTargetHeight; bool mQuitRequested; }; @@ -909,16 +909,16 @@ private: class LLMenuItemTearOffGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - {}; + struct Params : public LLInitParam::Block + {}; + + LLMenuItemTearOffGL( const Params& ); - LLMenuItemTearOffGL( const Params& ); - - virtual void onCommit(void); - virtual void draw(void); - virtual U32 getNominalHeight() const; + virtual void onCommit(void); + virtual void draw(void); + virtual U32 getNominalHeight() const; - LLFloater* getParentFloater(); + LLFloater* getParentFloater(); }; @@ -926,13 +926,13 @@ public: class LLEditMenuHandlerMgr { public: - LLEditMenuHandlerMgr& getInstance() { - static LLEditMenuHandlerMgr instance; - return instance; - } - virtual ~LLEditMenuHandlerMgr() {} + LLEditMenuHandlerMgr& getInstance() { + static LLEditMenuHandlerMgr instance; + return instance; + } + virtual ~LLEditMenuHandlerMgr() {} private: - LLEditMenuHandlerMgr() {}; + LLEditMenuHandlerMgr() {}; }; @@ -941,40 +941,40 @@ private: class view_listener_t : public boost::signals2::trackable { public: - virtual bool handleEvent(const LLSD& userdata) = 0; - view_listener_t() { sListeners.insert(this); } - virtual ~view_listener_t() { sListeners.erase(this); } - - static void addEnable(view_listener_t* listener, const std::string& name) - { - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addCommit(view_listener_t* listener, const std::string& name) - { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addMenu(view_listener_t* listener, const std::string& name) - { - // For now, add to both click and enable registries - addEnable(listener, name); - addCommit(listener, name); - } - - static void cleanup() - { - listener_vector_t listeners(sListeners.begin(), sListeners.end()); - sListeners.clear(); - - std::for_each(listeners.begin(), listeners.end(), DeletePointer()); - listeners.clear(); - } + virtual bool handleEvent(const LLSD& userdata) = 0; + view_listener_t() { sListeners.insert(this); } + virtual ~view_listener_t() { sListeners.erase(this); } + + static void addEnable(view_listener_t* listener, const std::string& name) + { + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addCommit(view_listener_t* listener, const std::string& name) + { + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addMenu(view_listener_t* listener, const std::string& name) + { + // For now, add to both click and enable registries + addEnable(listener, name); + addCommit(listener, name); + } + + static void cleanup() + { + listener_vector_t listeners(sListeners.begin(), sListeners.end()); + sListeners.clear(); + + std::for_each(listeners.begin(), listeners.end(), DeletePointer()); + listeners.clear(); + } private: - typedef std::set listener_map_t; - typedef std::vector listener_vector_t; - static listener_map_t sListeners; + typedef std::set listener_map_t; + typedef std::vector listener_vector_t; + static listener_map_t sListeners; }; #endif // LL_LLMENUGL_H diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index d6fc7d5377..348a4603de 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltexteditor.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR #include "llfontgl.h" -#include "llgl.h" // LLGLSUIDefault() +#include "llgl.h" // LLGLSUIDefault() #include "lllocalcliprect.h" #include "llrender.h" #include "llui.h" @@ -64,105 +64,105 @@ #include #include "llcombobox.h" -// +// // Globals // static LLDefaultChildRegistry::Register r("simple_text_editor"); // Compiler optimization, generate extern template template class LLTextEditor* LLView::getChild( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; // // Constants // -const S32 SPACES_PER_TAB = 4; -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on +const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd { public: - TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(ws) - { - } - virtual ~TextCmdInsert() {} - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString ); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(ws) + { + } + virtual ~TextCmdInsert() {} + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString ); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; + LLWString mWString; }; /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd { public: - TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) - { - } - virtual void blockExtensions() - { - mBlockExtensions = TRUE; - } - virtual BOOL canExtend(S32 pos) const - { - // cannot extend text with custom segments - if (!mSegments.empty()) return FALSE; - - return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) - { - LLWString ws; - ws += wc; - - *delta = insert(editor, pos, ws); - if( *delta > 0 ) - { - mWString += wc; - } - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) + { + } + virtual void blockExtensions() + { + mBlockExtensions = TRUE; + } + virtual BOOL canExtend(S32 pos) const + { + // cannot extend text with custom segments + if (!mSegments.empty()) return FALSE; + + return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) + { + LLWString ws; + ws += wc; + + *delta = insert(editor, pos, ws); + if( *delta > 0 ) + { + mWString += wc; + } + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; - BOOL mBlockExtensions; + LLWString mWString; + BOOL mBlockExtensions; }; @@ -171,30 +171,30 @@ private: class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd { public: - TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) - : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} - - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mOldChar = editor->getWText()[getPosition()]; - overwrite(editor, getPosition(), mChar); - *delta = 0; - return TRUE; - } - virtual S32 undo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mOldChar); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mChar); - return getPosition()+1; - } + TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) + : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} + + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mOldChar = editor->getWText()[getPosition()]; + overwrite(editor, getPosition(), mChar); + *delta = 0; + return TRUE; + } + virtual S32 undo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mOldChar); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mChar); + return getPosition()+1; + } private: - llwchar mChar; - llwchar mOldChar; + llwchar mChar; + llwchar mOldChar; }; /////////////////////////////////////////////////////////////////// @@ -202,114 +202,114 @@ private: class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd { public: - TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : - TextCmd(pos, group_with_next), mLen(len) - { - std::swap(mSegments, segments); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mWString = editor->getWText().substr(getPosition(), mLen); - *delta = remove(editor, getPosition(), mLen ); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString); - return getPosition() + mWString.length(); - } - virtual S32 redo( LLTextBase* editor ) - { - remove(editor, getPosition(), mLen ); - return getPosition(); - } + TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : + TextCmd(pos, group_with_next), mLen(len) + { + std::swap(mSegments, segments); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mWString = editor->getWText().substr(getPosition(), mLen); + *delta = remove(editor, getPosition(), mLen ); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString); + return getPosition() + mWString.length(); + } + virtual S32 redo( LLTextBase* editor ) + { + remove(editor, getPosition(), mLen ); + return getPosition(); + } private: - LLWString mWString; - S32 mLen; + LLWString mWString; + S32 mLen; }; /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() -: default_text("default_text"), - prevalidate_callback("prevalidate_callback"), - embedded_items("embedded_items", false), - ignore_tab("ignore_tab", true), - auto_indent("auto_indent", true), - default_color("default_color"), +: default_text("default_text"), + prevalidate_callback("prevalidate_callback"), + embedded_items("embedded_items", false), + ignore_tab("ignore_tab", true), + auto_indent("auto_indent", true), + default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), - show_context_menu("show_context_menu"), - show_emoji_helper("show_emoji_helper"), - enable_tooltip_paste("enable_tooltip_paste") + show_context_menu("show_context_menu"), + show_emoji_helper("show_emoji_helper"), + enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidate_callback, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : - LLTextBase(p), - mAutoreplaceCallback(), - mBaseDocIsPristine(TRUE), - mPristineCmd( NULL ), - mLastCmd( NULL ), - mDefaultColor( p.default_color() ), - mAutoIndent(p.auto_indent), - mCommitOnFocusLost( p.commit_on_focus_lost), - mAllowEmbeddedItems( p.embedded_items ), - mMouseDownX(0), - mMouseDownY(0), - mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), - mShowContextMenu(p.show_context_menu), - mShowEmojiHelper(p.show_emoji_helper), - mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), - mKeepSelectionOnReturn(false) -{ - mSourceID.generate(); - - //FIXME: use image? - LLViewBorder::Params params; - params.name = "text ed border"; - params.rect = getLocalRect(); - params.bevel_style = LLViewBorder::BEVEL_IN; - params.border_thickness = 1; - params.visible = p.border_visible; - mBorder = LLUICtrlFactory::create (params); - addChild( mBorder ); - setText(p.default_text()); - - mParseOnTheFly = TRUE; + LLTextBase(p), + mAutoreplaceCallback(), + mBaseDocIsPristine(TRUE), + mPristineCmd( NULL ), + mLastCmd( NULL ), + mDefaultColor( p.default_color() ), + mAutoIndent(p.auto_indent), + mCommitOnFocusLost( p.commit_on_focus_lost), + mAllowEmbeddedItems( p.embedded_items ), + mMouseDownX(0), + mMouseDownY(0), + mTabsToNextField(p.ignore_tab), + mPrevalidateFunc(p.prevalidate_callback()), + mShowContextMenu(p.show_context_menu), + mShowEmojiHelper(p.show_emoji_helper), + mEnableTooltipPaste(p.enable_tooltip_paste), + mPassDelete(FALSE), + mKeepSelectionOnReturn(false) +{ + mSourceID.generate(); + + //FIXME: use image? + LLViewBorder::Params params; + params.name = "text ed border"; + params.rect = getLocalRect(); + params.bevel_style = LLViewBorder::BEVEL_IN; + params.border_thickness = 1; + params.visible = p.border_visible; + mBorder = LLUICtrlFactory::create (params); + addChild( mBorder ); + setText(p.default_text()); + + mParseOnTheFly = TRUE; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) { - LLTextBase::initFromParams(p); + LLTextBase::initFromParams(p); - // HACK: text editors always need to be enabled so that we can scroll - LLView::setEnabled(true); + // HACK: text editors always need to be enabled so that we can scroll + LLView::setEnabled(true); + + if (p.commit_on_focus_lost.isProvided()) + { + mCommitOnFocusLost = p.commit_on_focus_lost; + } - if (p.commit_on_focus_lost.isProvided()) - { - mCommitOnFocusLost = p.commit_on_focus_lost; - } - - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); } LLTextEditor::~LLTextEditor() { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid - // Scrollbar is deleted by LLView - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); - // Mark the menu as dead or its retained in memory till shutdown. - LLContextMenu* menu = static_cast(mContextMenuHandle.get()); - if(menu) - { - menu->die(); - mContextMenuHandle.markDead(); - } + // Scrollbar is deleted by LLView + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); + // Mark the menu as dead or its retained in memory till shutdown. + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if(menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } } //////////////////////////////////////////////////////////// @@ -318,649 +318,649 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { - // validate incoming text if necessary - if (mPrevalidateFunc) - { - LLWString test_text = utf8str_to_wstring(utf8str); - if (!mPrevalidateFunc(test_text)) - { - // not valid text, nothing to do - return; - } - } + // validate incoming text if necessary + if (mPrevalidateFunc) + { + LLWString test_text = utf8str_to_wstring(utf8str); + if (!mPrevalidateFunc(test_text)) + { + // not valid text, nothing to do + return; + } + } - blockUndo(); - deselect(); - - mParseOnTheFly = FALSE; - LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + blockUndo(); + deselect(); - resetDirty(); + mParseOnTheFly = FALSE; + LLTextBase::setText(utf8str, input_params); + mParseOnTheFly = TRUE; + + resetDirty(); } void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap) { - if (search_text_in.empty()) - { - return; - } - - LLWString text = getWText(); - LLWString search_text = utf8str_to_wstring(search_text_in); - if (case_insensitive) - { - LLWStringUtil::toLower(text); - LLWStringUtil::toLower(search_text); - } - - if (mIsSelecting) - { - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - - if (selected_text == search_text) - { - // We already have this word selected, we are searching for the next. - setCursorPos(mCursorPos + search_text.size()); - } - } - - S32 loc = text.find(search_text,mCursorPos); - - // If Maybe we wrapped, search again - if (wrap && (-1 == loc)) - { - loc = text.find(search_text); - } - - // If still -1, then search_text just isn't found. + if (search_text_in.empty()) + { + return; + } + + LLWString text = getWText(); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (case_insensitive) + { + LLWStringUtil::toLower(text); + LLWStringUtil::toLower(search_text); + } + + if (mIsSelecting) + { + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + + if (selected_text == search_text) + { + // We already have this word selected, we are searching for the next. + setCursorPos(mCursorPos + search_text.size()); + } + } + + S32 loc = text.find(search_text,mCursorPos); + + // If Maybe we wrapped, search again + if (wrap && (-1 == loc)) + { + loc = text.find(search_text); + } + + // If still -1, then search_text just isn't found. if (-1 == loc) - { - mIsSelecting = FALSE; - mSelectionEnd = 0; - mSelectionStart = 0; - return; - } + { + mIsSelecting = FALSE; + mSelectionEnd = 0; + mSelectionStart = 0; + return; + } + + setCursorPos(loc); - setCursorPos(loc); - - mIsSelecting = TRUE; - mSelectionEnd = mCursorPos; - mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); + mIsSelecting = TRUE; + mSelectionEnd = mCursorPos; + mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text, - BOOL case_insensitive, BOOL wrap) + BOOL case_insensitive, BOOL wrap) { - BOOL replaced = FALSE; + BOOL replaced = FALSE; - if (search_text_in.empty()) - { - return replaced; - } + if (search_text_in.empty()) + { + return replaced; + } - LLWString search_text = utf8str_to_wstring(search_text_in); - if (mIsSelecting) - { - LLWString text = getWText(); - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (mIsSelecting) + { + LLWString text = getWText(); + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - if (case_insensitive) - { - LLWStringUtil::toLower(selected_text); - LLWStringUtil::toLower(search_text); - } + if (case_insensitive) + { + LLWStringUtil::toLower(selected_text); + LLWStringUtil::toLower(search_text); + } - if (selected_text == search_text) - { - insertText(replace_text); - replaced = TRUE; - } - } + if (selected_text == search_text) + { + insertText(replace_text); + replaced = TRUE; + } + } - selectNext(search_text_in, case_insensitive, wrap); - return replaced; + selectNext(search_text_in, case_insensitive, wrap); + return replaced; } void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive) { - startOfDoc(); - selectNext(search_text, case_insensitive, FALSE); + startOfDoc(); + selectNext(search_text, case_insensitive, FALSE); - BOOL replaced = TRUE; - while ( replaced ) - { - replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); - } + BOOL replaced = TRUE; + while ( replaced ) + { + replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); + } } S32 LLTextEditor::prevWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) - { - cursorPos--; - } - while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) - { - cursorPos--; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) + { + cursorPos--; + } + while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) + { + cursorPos--; + } + return cursorPos; } S32 LLTextEditor::nextWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) - { - cursorPos++; - } - while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) - { - cursorPos++; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) + { + cursorPos++; + } + while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) + { + cursorPos++; + } + return cursorPos; } -const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const +const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const { - static LLPointer index_segment = new LLIndexSegment; + static LLPointer index_segment = new LLIndexSegment; - index_segment->setStart(mCursorPos); - index_segment->setEnd(mCursorPos); + index_segment->setStart(mCursorPos); + index_segment->setEnd(mCursorPos); - // find segment index at character to left of cursor (or rightmost edge of selection) - segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); + // find segment index at character to left of cursor (or rightmost edge of selection) + segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); - if (it != mSegments.end()) - { - return *it; - } - else - { - return LLTextSegmentPtr(); - } + if (it != mSegments.end()) + { + return *it; + } + else + { + return LLTextSegmentPtr(); + } } void LLTextEditor::getSelectedSegments(LLTextEditor::segment_vec_t& segments) const { - S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; - S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; - return getSegmentsInRange(segments, left, right, true); + return getSegmentsInRange(segments, left, right, true); } void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, S32 start, S32 end, bool include_partial) const { - segment_set_t::const_iterator first_it = getSegIterContaining(start); - segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); - if (end_it != mSegments.end()) ++end_it; + segment_set_t::const_iterator first_it = getSegIterContaining(start); + segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); + if (end_it != mSegments.end()) ++end_it; - for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) - { - LLTextSegmentPtr segment = *it; - if (include_partial - || (segment->getStart() >= start - && segment->getEnd() <= end)) - { - segments_out.push_back(segment); - } - } + for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) + { + LLTextSegmentPtr segment = *it; + if (include_partial + || (segment->getStart() >= start + && segment->getEnd() <= end)) + { + segments_out.push_back(segment); + } + } } void LLTextEditor::setShowEmojiHelper(bool show) { - if (!mShowEmojiHelper) - { - LLEmojiHelper::instance().hideHelper(this); - } + if (!mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } - mShowEmojiHelper = show; + mShowEmojiHelper = show; } BOOL LLTextEditor::selectionContainsLineBreaks() { - if (hasSelection()) - { - S32 left = llmin(mSelectionStart, mSelectionEnd); - S32 right = left + llabs(mSelectionStart - mSelectionEnd); + if (hasSelection()) + { + S32 left = llmin(mSelectionStart, mSelectionEnd); + S32 right = left + llabs(mSelectionStart - mSelectionEnd); - LLWString wtext = getWText(); - for( S32 i = left; i < right; i++ ) - { - if (wtext[i] == '\n') - { - return TRUE; - } - } - } - return FALSE; + LLWString wtext = getWText(); + for( S32 i = left; i < right; i++ ) + { + if (wtext[i] == '\n') + { + return TRUE; + } + } + } + return FALSE; } S32 LLTextEditor::indentLine( S32 pos, S32 spaces ) { - // Assumes that pos is at the start of the line - // spaces may be positive (indent) or negative (unindent). - // Returns the actual number of characters added or removed. - - llassert(pos >= 0); - llassert(pos <= getLength() ); - - S32 delta_spaces = 0; - - if (spaces >= 0) - { - // Indent - for(S32 i=0; i < spaces; i++) - { - delta_spaces += addChar(pos, ' '); - } - } - else - { - // Unindent - for(S32 i=0; i < -spaces; i++) - { - LLWString wtext = getWText(); - if (wtext[pos] == ' ') - { - delta_spaces += remove( pos, 1, FALSE ); - } - } - } - - return delta_spaces; + // Assumes that pos is at the start of the line + // spaces may be positive (indent) or negative (unindent). + // Returns the actual number of characters added or removed. + + llassert(pos >= 0); + llassert(pos <= getLength() ); + + S32 delta_spaces = 0; + + if (spaces >= 0) + { + // Indent + for(S32 i=0; i < spaces; i++) + { + delta_spaces += addChar(pos, ' '); + } + } + else + { + // Unindent + for(S32 i=0; i < -spaces; i++) + { + LLWString wtext = getWText(); + if (wtext[pos] == ' ') + { + delta_spaces += remove( pos, 1, FALSE ); + } + } + } + + return delta_spaces; } void LLTextEditor::indentSelectedLines( S32 spaces ) { - if( hasSelection() ) - { - LLWString text = getWText(); - S32 left = llmin( mSelectionStart, mSelectionEnd ); - S32 right = left + llabs( mSelectionStart - mSelectionEnd ); - BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); - S32 cur = left; - - // Expand left to start of line - while( (cur > 0) && (text[cur] != '\n') ) - { - cur--; - } - left = cur; - if( cur > 0 ) - { - left++; - } - - // Expand right to end of line - if( text[right - 1] == '\n' ) - { - right--; - } - else - { - while( (text[right] != '\n') && (right <= getLength() ) ) - { - right++; - } - } - - // Disabling parsing on the fly to avoid updating text segments - // until all indentation commands are executed. - mParseOnTheFly = FALSE; - - // Find each start-of-line and indent it - do - { - if( text[cur] == '\n' ) - { - cur++; - } - - S32 delta_spaces = indentLine( cur, spaces ); - if( delta_spaces > 0 ) - { - cur += delta_spaces; - } - right += delta_spaces; - - text = getWText(); - - // Find the next new line - while( (cur < right) && (text[cur] != '\n') ) - { - cur++; - } - } - while( cur < right ); - - mParseOnTheFly = TRUE; - - if( (right < getLength()) && (text[right] == '\n') ) - { - right++; - } - - // Set the selection and cursor - if( cursor_on_right ) - { - mSelectionStart = left; - mSelectionEnd = right; - } - else - { - mSelectionStart = right; - mSelectionEnd = left; - } - setCursorPos(mSelectionEnd); - } + if( hasSelection() ) + { + LLWString text = getWText(); + S32 left = llmin( mSelectionStart, mSelectionEnd ); + S32 right = left + llabs( mSelectionStart - mSelectionEnd ); + BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); + S32 cur = left; + + // Expand left to start of line + while( (cur > 0) && (text[cur] != '\n') ) + { + cur--; + } + left = cur; + if( cur > 0 ) + { + left++; + } + + // Expand right to end of line + if( text[right - 1] == '\n' ) + { + right--; + } + else + { + while( (text[right] != '\n') && (right <= getLength() ) ) + { + right++; + } + } + + // Disabling parsing on the fly to avoid updating text segments + // until all indentation commands are executed. + mParseOnTheFly = FALSE; + + // Find each start-of-line and indent it + do + { + if( text[cur] == '\n' ) + { + cur++; + } + + S32 delta_spaces = indentLine( cur, spaces ); + if( delta_spaces > 0 ) + { + cur += delta_spaces; + } + right += delta_spaces; + + text = getWText(); + + // Find the next new line + while( (cur < right) && (text[cur] != '\n') ) + { + cur++; + } + } + while( cur < right ); + + mParseOnTheFly = TRUE; + + if( (right < getLength()) && (text[right] == '\n') ) + { + right++; + } + + // Set the selection and cursor + if( cursor_on_right ) + { + mSelectionStart = left; + mSelectionEnd = right; + } + else + { + mSelectionStart = right; + mSelectionEnd = left; + } + setCursorPos(mSelectionEnd); + } } //virtual BOOL LLTextEditor::canSelectAll() const { - return TRUE; + return TRUE; } // virtual void LLTextEditor::selectAll() { - mSelectionStart = getLength(); - mSelectionEnd = 0; - setCursorPos(mSelectionEnd); - updatePrimary(); + mSelectionStart = getLength(); + mSelectionEnd = 0; + setCursorPos(mSelectionEnd); + updatePrimary(); } void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos) { - setCursorPos(prev_cursor_pos); - startSelection(); - setCursorPos(next_cursor_pos); - endSelection(); + setCursorPos(prev_cursor_pos); + startSelection(); + setCursorPos(next_cursor_pos); + endSelection(); } void LLTextEditor::insertEmoji(llwchar emoji) { - LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; - auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); - auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); - insert(mCursorPos, LLWString(1, emoji), false, segment); - setCursorPos(mCursorPos + 1); + LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmoji(); + auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); + insert(mCursorPos, LLWString(1, emoji), false, segment); + setCursorPos(mCursorPos + 1); } void LLTextEditor::handleEmojiCommit(llwchar emoji) { - S32 shortCodePos; - if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) - { - remove(shortCodePos, mCursorPos - shortCodePos, true); - setCursorPos(shortCodePos); + S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) + { + remove(shortCodePos, mCursorPos - shortCodePos, true); + setCursorPos(shortCodePos); - insertEmoji(emoji); - } + insertEmoji(emoji); + } } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // set focus first, in case click callbacks want to change it - // RN: do we really need to have a tab stop? - if (hasTabStop()) - { - setFocus( TRUE ); - } - - // Let scrollbar have first dibs - handled = LLTextBase::handleMouseDown(x, y, mask); - - if( !handled ) - { - if (!(mask & MASK_SHIFT)) - { - deselect(); - } - - BOOL start_select = TRUE; - if( start_select ) - { - // If we're not scrolling (handled by child), then we're selecting - if (mask & MASK_SHIFT) - { - S32 old_cursor_pos = mCursorPos; - setCursorAtLocalPos( x, y, true ); - - if (hasSelection()) - { - mSelectionEnd = mCursorPos; - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = mCursorPos; - } - // assume we're starting a drag select - mIsSelecting = TRUE; - } - else - { - setCursorAtLocalPos( x, y, true ); - startSelection(); - } - } - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if (handled && !gFocusMgr.getMouseCapture()) - { - gFocusMgr.setMouseCapture( this ); - } - return handled; + BOOL handled = FALSE; + + // set focus first, in case click callbacks want to change it + // RN: do we really need to have a tab stop? + if (hasTabStop()) + { + setFocus( TRUE ); + } + + // Let scrollbar have first dibs + handled = LLTextBase::handleMouseDown(x, y, mask); + + if( !handled ) + { + if (!(mask & MASK_SHIFT)) + { + deselect(); + } + + BOOL start_select = TRUE; + if( start_select ) + { + // If we're not scrolling (handled by child), then we're selecting + if (mask & MASK_SHIFT) + { + S32 old_cursor_pos = mCursorPos; + setCursorAtLocalPos( x, y, true ); + + if (hasSelection()) + { + mSelectionEnd = mCursorPos; + } + else + { + mSelectionStart = old_cursor_pos; + mSelectionEnd = mCursorPos; + } + // assume we're starting a drag select + mIsSelecting = TRUE; + } + else + { + setCursorAtLocalPos( x, y, true ); + startSelection(); + } + } + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if (handled && !gFocusMgr.getMouseCapture()) + { + gFocusMgr.setMouseCapture( this ); + } + return handled; } BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - bool show_menu = false; + bool show_menu = false; - // Prefer editor menu if it has selection. See EXT-6806. - if (hasSelection()) - { - S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); - if (click_pos > mSelectionStart && click_pos < mSelectionEnd) - { - show_menu = true; - } - } + // Prefer editor menu if it has selection. See EXT-6806. + if (hasSelection()) + { + S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); + if (click_pos > mSelectionStart && click_pos < mSelectionEnd) + { + show_menu = true; + } + } - // Let segments handle the click, if nothing does, show editor menu - if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) - { - show_menu = true; - } + // Let segments handle the click, if nothing does, show editor menu + if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) + { + show_menu = true; + } - if (show_menu && getShowContextMenu()) - { - showContextMenu(x, y); - } + if (show_menu && getShowContextMenu()) + { + showContextMenu(x, y); + } - return TRUE; + return TRUE; } BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - if (!LLTextBase::handleMouseDown(x, y, mask)) - { - if( canPastePrimary() ) - { - setCursorAtLocalPos( x, y, true ); - // does not rely on focus being set - pastePrimary(); - } - } - return TRUE; + if (!LLTextBase::handleMouseDown(x, y, mask)) + { + if( canPastePrimary() ) + { + setCursorAtLocalPos( x, y, true ); + // does not rely on focus being set + pastePrimary(); + } + } + return TRUE; } BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if(hasMouseCapture() ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - mSelectionEnd = mCursorPos; - } - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - if( !handled ) - { - // Pass to children - handled = LLTextBase::handleHover(x, y, mask); - } - - if( handled ) - { - // Delay cursor flashing - resetCursorBlink(); - } - - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + if(hasMouseCapture() ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + mSelectionEnd = mCursorPos; + } + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + if( !handled ) + { + // Pass to children + handled = LLTextBase::handleHover(x, y, mask); + } + + if( handled ) + { + // Delay cursor flashing + resetCursorBlink(); + } + + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // if I'm not currently selecting text - if (!(mIsSelecting && hasMouseCapture())) - { - // let text segments handle mouse event - handled = LLTextBase::handleMouseUp(x, y, mask); - } - - if( !handled ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - endSelection(); - } - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + // if I'm not currently selecting text + if (!(mIsSelecting && hasMouseCapture())) + { + // let text segments handle mouse event + handled = LLTextBase::handleMouseUp(x, y, mask); + } + + if( !handled ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + endSelection(); + } + + // take selection to 'primary' clipboard + updatePrimary(); + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - // let scrollbar and text segments have first dibs - handled = LLTextBase::handleDoubleClick(x, y, mask); + // let scrollbar and text segments have first dibs + handled = LLTextBase::handleDoubleClick(x, y, mask); - if( !handled ) - { - setCursorAtLocalPos( x, y, false ); - deselect(); + if( !handled ) + { + setCursorAtLocalPos( x, y, false ); + deselect(); - LLWString text = getWText(); - - if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) - { - if (!setCursorPos(mCursorPos - 1)) break; - } - startSelection(); + LLWString text = getWText(); - while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - if (!setCursorPos(mCursorPos + 1)) break; - } - - mSelectionEnd = mCursorPos; - } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - setCursorPos(mCursorPos + 1); - mSelectionEnd = mCursorPos; - } + if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + // Select word the cursor is over + while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) + { + if (!setCursorPos(mCursorPos - 1)) break; + } + startSelection(); + + while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + if (!setCursorPos(mCursorPos + 1)) break; + } + + mSelectionEnd = mCursorPos; + } + else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) + { + // Select the character the cursor is over + startSelection(); + setCursorPos(mCursorPos + 1); + mSelectionEnd = mCursorPos; + } - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection here. + mIsSelecting = FALSE; - // delay cursor flashing - resetCursorBlink(); + // delay cursor flashing + resetCursorBlink(); - // take selection to 'primary' clipboard - updatePrimary(); + // take selection to 'primary' clipboard + updatePrimary(); - handled = TRUE; - } + handled = TRUE; + } - return handled; + return handled; } @@ -969,228 +969,228 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) S32 LLTextEditor::execute( TextCmd* cmd ) { - if (!mReadOnly && mShowEmojiHelper) - { - // Any change to our contents should always hide the helper - LLEmojiHelper::instance().hideHelper(this); - } - - S32 delta = 0; - if( cmd->execute(this, &delta) ) - { - // Delete top of undo stack - undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - std::for_each(mUndoStack.begin(), enditer, DeletePointer()); - mUndoStack.erase(mUndoStack.begin(), enditer); - // Push the new command is now on the top (front) of the undo stack. - mUndoStack.push_front(cmd); - mLastCmd = cmd; - - bool need_to_rollback = mPrevalidateFunc - && !mPrevalidateFunc(getViewModel()->getDisplay()); - if (need_to_rollback) - { - // get rid of this last command and clean up undo stack - undo(); - - // remove any evidence of this command from redo history - mUndoStack.pop_front(); - delete cmd; - - // failure, nothing changed - delta = 0; - } - } - else - { - // Operation failed, so don't put it on the undo stack. - delete cmd; - } - - return delta; + if (!mReadOnly && mShowEmojiHelper) + { + // Any change to our contents should always hide the helper + LLEmojiHelper::instance().hideHelper(this); + } + + S32 delta = 0; + if( cmd->execute(this, &delta) ) + { + // Delete top of undo stack + undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + std::for_each(mUndoStack.begin(), enditer, DeletePointer()); + mUndoStack.erase(mUndoStack.begin(), enditer); + // Push the new command is now on the top (front) of the undo stack. + mUndoStack.push_front(cmd); + mLastCmd = cmd; + + bool need_to_rollback = mPrevalidateFunc + && !mPrevalidateFunc(getViewModel()->getDisplay()); + if (need_to_rollback) + { + // get rid of this last command and clean up undo stack + undo(); + + // remove any evidence of this command from redo history + mUndoStack.pop_front(); + delete cmd; + + // failure, nothing changed + delta = 0; + } + } + else + { + // Operation failed, so don't put it on the undo stack. + delete cmd; + } + + return delta; } S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment) { - return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); + return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); } S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op) { - S32 end_pos = getEditableIndex(pos + length, true); - BOOL removedChar = FALSE; + S32 end_pos = getEditableIndex(pos + length, true); + BOOL removedChar = FALSE; + + segment_vec_t segments_to_remove; + // store text segments + getSegmentsInRange(segments_to_remove, pos, pos + length, false); - segment_vec_t segments_to_remove; - // store text segments - getSegmentsInRange(segments_to_remove, pos, pos + length, false); - - if (pos <= end_pos) - { - removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); - } + if (pos <= end_pos) + { + removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); + } - return removedChar; + return removedChar; } S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) { - if ((S32)getLength() == pos) - { - return addChar(pos, wc); - } - else - { - return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); - } + if ((S32)getLength() == pos) + { + return addChar(pos, wc); + } + else + { + return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); + } } // Remove a single character from the text. Tries to remove // a pseudo-tab (up to for spaces in a row) void LLTextEditor::removeCharOrTab() { - if (!getEnabled()) - { - return; - } - - if (mCursorPos > 0) - { - S32 chars_to_remove = 1; - - LLWString text = getWText(); - if (text[mCursorPos - 1] == ' ') - { - // Try to remove a "tab" - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - if (offset > 0) - { - chars_to_remove = offset % SPACES_PER_TAB; - if (chars_to_remove == 0) - { - chars_to_remove = SPACES_PER_TAB; - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - if (text[mCursorPos - i - 1] != ' ') - { - // Fewer than a full tab's worth of spaces, so - // just delete a single character. - chars_to_remove = 1; - break; - } - } - } - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - setCursorPos(mCursorPos - 1); - remove(mCursorPos, 1, false); - } - - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } -} + if (!getEnabled()) + { + return; + } -// Remove a single character from the text -S32 LLTextEditor::removeChar(S32 pos) -{ - return remove(pos, 1, false); + if (mCursorPos > 0) + { + S32 chars_to_remove = 1; + + LLWString text = getWText(); + if (text[mCursorPos - 1] == ' ') + { + // Try to remove a "tab" + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + if (offset > 0) + { + chars_to_remove = offset % SPACES_PER_TAB; + if (chars_to_remove == 0) + { + chars_to_remove = SPACES_PER_TAB; + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + if (text[mCursorPos - i - 1] != ' ') + { + // Fewer than a full tab's worth of spaces, so + // just delete a single character. + chars_to_remove = 1; + break; + } + } + } + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + setCursorPos(mCursorPos - 1); + remove(mCursorPos, 1, false); + } + + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } +} + +// Remove a single character from the text +S32 LLTextEditor::removeChar(S32 pos) +{ + return remove(pos, 1, false); } void LLTextEditor::removeChar() { - if (!getEnabled()) - { - return; - } + if (!getEnabled()) + { + return; + } - if (mCursorPos > 0) - { - setCursorPos(mCursorPos - 1); - removeChar(mCursorPos); - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (mCursorPos > 0) + { + setCursorPos(mCursorPos - 1); + removeChar(mCursorPos); + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) - { - make_ui_sound("UISndBadKeystroke"); - return 0; - } - - if (mLastCmd && mLastCmd->canExtend(pos)) - { - S32 delta = 0; - if (mPrevalidateFunc) - { - // get a copy of current text contents - LLWString test_string(getViewModel()->getDisplay()); - - // modify text contents as if this addChar succeeded - llassert(pos <= (S32)test_string.size()); - test_string.insert(pos, 1, wc); - if (!mPrevalidateFunc( test_string)) - { - return 0; - } - } - mLastCmd->extendAndExecute(this, pos, wc, &delta); - - return delta; - } - else - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) + { + make_ui_sound("UISndBadKeystroke"); + return 0; + } + + if (mLastCmd && mLastCmd->canExtend(pos)) + { + S32 delta = 0; + if (mPrevalidateFunc) + { + // get a copy of current text contents + LLWString test_string(getViewModel()->getDisplay()); + + // modify text contents as if this addChar succeeded + llassert(pos <= (S32)test_string.size()); + test_string.insert(pos, 1, wc); + if (!mPrevalidateFunc( test_string)) + { + return 0; + } + } + mLastCmd->extendAndExecute(this, pos, wc, &delta); + + return delta; + } + else + { + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); + } } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } - - setCursorPos(mCursorPos + addChar( mCursorPos, wc )); - tryToShowEmojiHelper(); - - if (!mReadOnly && mAutoreplaceCallback != NULL) - { - // autoreplace the text, if necessary - S32 replacement_start; - S32 replacement_length; - LLWString replacement_string; - S32 new_cursor_pos = mCursorPos; - mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); - - if (replacement_length > 0 || !replacement_string.empty()) - { - remove(replacement_start, replacement_length, true); - insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); - setCursorPos(new_cursor_pos); - } - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + setCursorPos(mCursorPos + addChar( mCursorPos, wc )); + tryToShowEmojiHelper(); + + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // autoreplace the text, if necessary + S32 replacement_start; + S32 replacement_length; + LLWString replacement_string; + S32 new_cursor_pos = mCursorPos; + mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); + + if (replacement_length > 0 || !replacement_string.empty()) + { + remove(replacement_start, replacement_length, true); + insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); + setCursorPos(new_cursor_pos); + } + } } void LLTextEditor::showEmojiHelper() @@ -1226,792 +1226,792 @@ void LLTextEditor::tryToShowEmojiHelper() void LLTextEditor::addLineBreakChar(BOOL group_together) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + LLStyleConstSP sp(new LLStyle(LLStyle::Params())); + LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); - LLStyleConstSP sp(new LLStyle(LLStyle::Params())); - LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); + S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - - setCursorPos(mCursorPos + pos); + setCursorPos(mCursorPos + pos); } BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - if( mask & MASK_SHIFT ) - { - handled = TRUE; - - switch( key ) - { - case KEY_LEFT: - if( 0 < mCursorPos ) - { - startSelection(); - setCursorPos(mCursorPos - 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(prevWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - startSelection(); - setCursorPos(mCursorPos + 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(nextWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_UP: - startSelection(); - changeLine( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_UP: - startSelection(); - changePage( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_HOME: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(0); - } - else - { - startOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - case KEY_DOWN: - startSelection(); - changeLine( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_DOWN: - startSelection(); - changePage( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_END: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(getLength()); - } - else - { - endOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - default: - handled = FALSE; - break; - } - } - - if( handled ) - { - // take selection to 'primary' clipboard - updatePrimary(); - } - - return handled; + BOOL handled = FALSE; + + if( mask & MASK_SHIFT ) + { + handled = TRUE; + + switch( key ) + { + case KEY_LEFT: + if( 0 < mCursorPos ) + { + startSelection(); + setCursorPos(mCursorPos - 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(prevWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + startSelection(); + setCursorPos(mCursorPos + 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(nextWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_UP: + startSelection(); + changeLine( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_UP: + startSelection(); + changePage( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_HOME: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(0); + } + else + { + startOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + case KEY_DOWN: + startSelection(); + changeLine( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_DOWN: + startSelection(); + changePage( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_END: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(getLength()); + } + else + { + endOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + default: + handled = FALSE; + break; + } + } + + if( handled ) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + + return handled; } BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - // Ignore capslock key - if( MASK_NONE == mask ) - { - handled = TRUE; - switch( key ) - { - case KEY_UP: - changeLine( -1 ); - break; - - case KEY_PAGE_UP: - changePage( -1 ); - break; - - case KEY_HOME: - startOfLine(); - break; - - case KEY_DOWN: - changeLine( 1 ); - deselect(); - break; - - case KEY_PAGE_DOWN: - changePage( 1 ); - break; - - case KEY_END: - endOfLine(); - break; - - case KEY_LEFT: - if( hasSelection() ) - { - setCursorPos(llmin( mSelectionStart, mSelectionEnd )); - } - else - { - if( 0 < mCursorPos ) - { - setCursorPos(mCursorPos - 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - case KEY_RIGHT: - if( hasSelection() ) - { - setCursorPos(llmax( mSelectionStart, mSelectionEnd )); - } - else - { - if( mCursorPos < getLength() ) - { - setCursorPos(mCursorPos + 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled) - { - deselect(); - } - - return handled; + BOOL handled = FALSE; + + // Ignore capslock key + if( MASK_NONE == mask ) + { + handled = TRUE; + switch( key ) + { + case KEY_UP: + changeLine( -1 ); + break; + + case KEY_PAGE_UP: + changePage( -1 ); + break; + + case KEY_HOME: + startOfLine(); + break; + + case KEY_DOWN: + changeLine( 1 ); + deselect(); + break; + + case KEY_PAGE_DOWN: + changePage( 1 ); + break; + + case KEY_END: + endOfLine(); + break; + + case KEY_LEFT: + if( hasSelection() ) + { + setCursorPos(llmin( mSelectionStart, mSelectionEnd )); + } + else + { + if( 0 < mCursorPos ) + { + setCursorPos(mCursorPos - 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + case KEY_RIGHT: + if( hasSelection() ) + { + setCursorPos(llmax( mSelectionStart, mSelectionEnd )); + } + else + { + if( mCursorPos < getLength() ) + { + setCursorPos(mCursorPos + 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled) + { + deselect(); + } + + return handled; } void LLTextEditor::deleteSelection(BOOL group_with_next_op ) { - if( getEnabled() && hasSelection() ) - { - S32 pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - - remove( pos, length, group_with_next_op ); + if( getEnabled() && hasSelection() ) + { + S32 pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); - deselect(); - setCursorPos(pos); - } + remove( pos, length, group_with_next_op ); + + deselect(); + setCursorPos(pos); + } } // virtual BOOL LLTextEditor::canCut() const { - return !mReadOnly && hasSelection(); + return !mReadOnly && hasSelection(); } // cut selection to clipboard void LLTextEditor::cut() { - if( !canCut() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); - deleteSelection( FALSE ); + if( !canCut() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); + deleteSelection( FALSE ); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canCopy() const { - return hasSelection(); + return hasSelection(); } // copy selection to clipboard void LLTextEditor::copy() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(); + return !mReadOnly && LLClipboard::instance().isTextAvailable(); } // paste from clipboard void LLTextEditor::paste() { - bool is_primary = false; - pasteHelper(is_primary); + bool is_primary = false; + pasteHelper(is_primary); } // paste from primary void LLTextEditor::pastePrimary() { - bool is_primary = true; - pasteHelper(is_primary); + bool is_primary = true; + pasteHelper(is_primary); } // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; - bool can_paste_it; - if (is_primary) - { - can_paste_it = canPastePrimary(); - } - else - { - can_paste_it = canPaste(); - } + mParseOnTheFly = FALSE; + bool can_paste_it; + if (is_primary) + { + can_paste_it = canPastePrimary(); + } + else + { + can_paste_it = canPaste(); + } - if (!can_paste_it) - { - return; - } + if (!can_paste_it) + { + return; + } - LLWString paste; - LLClipboard::instance().pasteFromClipboard(paste, is_primary); + LLWString paste; + LLClipboard::instance().pasteFromClipboard(paste, is_primary); - if (paste.empty()) - { - return; - } + if (paste.empty()) + { + return; + } - // Delete any selected characters (the paste replaces them) - if( (!is_primary) && hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the paste replaces them) + if( (!is_primary) && hasSelection() ) + { + deleteSelection(TRUE); + } - // Clean up string (replace tabs and remove characters that our fonts don't support). - LLWString clean_string(paste); - cleanStringForPaste(clean_string); + // Clean up string (replace tabs and remove characters that our fonts don't support). + LLWString clean_string(paste); + cleanStringForPaste(clean_string); - // Insert the new text into the existing text. + // Insert the new text into the existing text. - //paste text with linebreaks. - pasteTextWithLinebreaks(clean_string); + //paste text with linebreaks. + pasteTextWithLinebreaks(clean_string); - deselect(); + deselect(); - onKeyStroke(); - mParseOnTheFly = TRUE; + onKeyStroke(); + mParseOnTheFly = TRUE; } // Clean up string (replace tabs and remove characters that our fonts don't support). void LLTextEditor::cleanStringForPaste(LLWString & clean_string) { - std::string clean_string_utf = wstring_to_utf8str(clean_string); - std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); - clean_string = utf8str_to_wstring(clean_string_utf); - - LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); - if( mAllowEmbeddedItems ) - { - const llwchar LF = 10; - S32 len = clean_string.length(); - for( S32 i = 0; i < len; i++ ) - { - llwchar wc = clean_string[i]; - if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) - { - clean_string[i] = LL_UNKNOWN_CHAR; - } - else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) - { - clean_string[i] = pasteEmbeddedItem(wc); - } - } - } + std::string clean_string_utf = wstring_to_utf8str(clean_string); + std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); + clean_string = utf8str_to_wstring(clean_string_utf); + + LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); + if( mAllowEmbeddedItems ) + { + const llwchar LF = 10; + S32 len = clean_string.length(); + for( S32 i = 0; i < len; i++ ) + { + llwchar wc = clean_string[i]; + if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) + { + clean_string[i] = LL_UNKNOWN_CHAR; + } + else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) + { + clean_string[i] = pasteEmbeddedItem(wc); + } + } + } } template <> void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) { - std::basic_string::size_type start = 0; - std::basic_string::size_type pos = clean_string.find('\n',start); - - while((pos != -1) && (pos != clean_string.length() -1)) - { - if(pos!=start) - { - std::basic_string str = std::basic_string(clean_string,start,pos-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); - } - addLineBreakChar(TRUE); // Add a line break and group with the next addition. - - start = pos+1; - pos = clean_string.find('\n',start); - } - - if (pos != start) - { - std::basic_string str = std::basic_string(clean_string,start,clean_string.length()-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); - } - else - { - addLineBreakChar(FALSE); // Add a line break and end the grouping. - } + std::basic_string::size_type start = 0; + std::basic_string::size_type pos = clean_string.find('\n',start); + + while((pos != -1) && (pos != clean_string.length() -1)) + { + if(pos!=start) + { + std::basic_string str = std::basic_string(clean_string,start,pos-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); + } + addLineBreakChar(TRUE); // Add a line break and group with the next addition. + + start = pos+1; + pos = clean_string.find('\n',start); + } + + if (pos != start) + { + std::basic_string str = std::basic_string(clean_string,start,clean_string.length()-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); + } + else + { + addLineBreakChar(FALSE); // Add a line break and end the grouping. + } } // copy selection to primary void LLTextEditor::copyPrimary() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(true); + return !mReadOnly && LLClipboard::instance().isTextAvailable(true); } void LLTextEditor::updatePrimary() { - if (canCopy()) - { - copyPrimary(); - } -} - -BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) -{ - BOOL handled = FALSE; - - if( mask & MASK_CONTROL ) - { - handled = TRUE; - - switch( key ) - { - case KEY_HOME: - if( mask & MASK_SHIFT ) - { - startSelection(); - setCursorPos(0); - mSelectionEnd = mCursorPos; - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - startOfDoc(); - } - break; - - case KEY_END: - { - if( mask & MASK_SHIFT ) - { - startSelection(); - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - } - endOfDoc(); - if( mask & MASK_SHIFT ) - { - mSelectionEnd = mCursorPos; - } - break; - } - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(nextWordPos(mCursorPos + 1)); - } - break; - - - case KEY_LEFT: - if( mCursorPos > 0 ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(prevWordPos(mCursorPos - 1)); - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled && !gFocusMgr.getMouseCapture()) - { - updatePrimary(); - } - - return handled; -} - - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) - { - BOOL handled = TRUE; - - if (mReadOnly) return FALSE; - - switch( key ) - { - case KEY_INSERT: - if (mask == MASK_NONE) - { - gKeyboard->toggleInsertMode(); - } - break; - - case KEY_BACKSPACE: - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( 0 < mCursorPos ) - { - removeCharOrTab(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - - case KEY_RETURN: - if (mask == MASK_NONE) - { - if( hasSelection() && !mKeepSelectionOnReturn ) - { - deleteSelection(FALSE); - } - if (mAutoIndent) - { - autoIndent(); - } - } - else - { - handled = FALSE; - break; - } - break; - - case KEY_TAB: - if (mask & MASK_CONTROL) - { - handled = FALSE; - break; - } - if( hasSelection() && selectionContainsLineBreaks() ) - { - indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); - } - else - { - if( hasSelection() ) - { - deleteSelection(FALSE); - } - - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - - S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - for( S32 i=0; i < spaces_needed; i++ ) - { - addChar( ' ' ); - } - } - break; - - default: - handled = FALSE; - break; - } - - if (handled) - { - onKeyStroke(); - } - return handled; + if (canCopy()) + { + copyPrimary(); + } } - -void LLTextEditor::unindentLineBeforeCloseBrace() +BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) { - if( mCursorPos >= 1 ) - { - LLWString text = getWText(); - if( ' ' == text[ mCursorPos - 1 ] ) - { - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); + BOOL handled = FALSE; + + if( mask & MASK_CONTROL ) + { + handled = TRUE; + + switch( key ) + { + case KEY_HOME: + if( mask & MASK_SHIFT ) + { + startSelection(); + setCursorPos(0); + mSelectionEnd = mCursorPos; + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + startOfDoc(); + } + break; + + case KEY_END: + { + if( mask & MASK_SHIFT ) + { + startSelection(); + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + } + endOfDoc(); + if( mask & MASK_SHIFT ) + { + mSelectionEnd = mCursorPos; + } + break; + } + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(nextWordPos(mCursorPos + 1)); + } + break; + + + case KEY_LEFT: + if( mCursorPos > 0 ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(prevWordPos(mCursorPos - 1)); + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled && !gFocusMgr.getMouseCapture()) + { + updatePrimary(); + } + + return handled; +} + + +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) + { + BOOL handled = TRUE; + + if (mReadOnly) return FALSE; + + switch( key ) + { + case KEY_INSERT: + if (mask == MASK_NONE) + { + gKeyboard->toggleInsertMode(); + } + break; + + case KEY_BACKSPACE: + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( 0 < mCursorPos ) + { + removeCharOrTab(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( hasSelection() && !mKeepSelectionOnReturn ) + { + deleteSelection(FALSE); + } + if (mAutoIndent) + { + autoIndent(); + } + } + else + { + handled = FALSE; + break; + } + break; + + case KEY_TAB: + if (mask & MASK_CONTROL) + { + handled = FALSE; + break; + } + if( hasSelection() && selectionContainsLineBreaks() ) + { + indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); + } + else + { + if( hasSelection() ) + { + deleteSelection(FALSE); + } + + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + + S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + for( S32 i=0; i < spaces_needed; i++ ) + { + addChar( ' ' ); + } + } + break; - // Jump over spaces in the current line - while ((' ' == text[line_start]) && (line_start < mCursorPos)) - { - line_start++; - } + default: + handled = FALSE; + break; + } - // Make sure there is nothing but ' ' before the Brace we are unindenting - if (line_start == mCursorPos) - { - removeCharOrTab(); - } - } - } + if (handled) + { + onKeyStroke(); + } + return handled; +} + + +void LLTextEditor::unindentLineBeforeCloseBrace() +{ + if( mCursorPos >= 1 ) + { + LLWString text = getWText(); + if( ' ' == text[ mCursorPos - 1 ] ) + { + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + + // Jump over spaces in the current line + while ((' ' == text[line_start]) && (line_start < mCursorPos)) + { + line_start++; + } + + // Make sure there is nothing but ' ' before the Brace we are unindenting + if (line_start == mCursorPos) + { + removeCharOrTab(); + } + } + } } BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - - // Special case for TAB. If want to move to next field, report - // not handled and let the parent take care of field movement. - if (KEY_TAB == key && mTabsToNextField) - { - return FALSE; - } - - if (mReadOnly && mScroller) - { - handled = (mScroller && mScroller->handleKeyHere( key, mask )) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask); - } - else - { - if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) - { - return TRUE; - } - - if (mEnableTooltipPaste && - LLToolTipMgr::instance().toolTipVisible() && + BOOL handled = FALSE; + + // Special case for TAB. If want to move to next field, report + // not handled and let the parent take care of field movement. + if (KEY_TAB == key && mTabsToNextField) + { + return FALSE; + } + + if (mReadOnly && mScroller) + { + handled = (mScroller && mScroller->handleKeyHere( key, mask )) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask); + } + else + { + if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + { + return TRUE; + } + + if (mEnableTooltipPaste && + LLToolTipMgr::instance().toolTipVisible() && LLToolTipMgr::instance().isTooltipPastable() && - KEY_TAB == key) - { // Paste the first line of a tooltip into the editor - std::string message; - LLToolTipMgr::instance().getToolTipMessage(message); - LLWString tool_tip_text(utf8str_to_wstring(message)); - - if (tool_tip_text.size() > 0) - { - // Delete any selected characters (the tooltip text replaces them) - if(hasSelection()) - { - deleteSelection(TRUE); - } - - std::basic_string::size_type pos = tool_tip_text.find('\n',0); - if (pos != -1) - { // Extract the first line of the tooltip - tool_tip_text = std::basic_string(tool_tip_text, 0, pos); - } - - // Add the text - cleanStringForPaste(tool_tip_text); - pasteTextWithLinebreaks(tool_tip_text); - handled = TRUE; - } - } - else - { // Normal key handling - handled = handleNavigationKey( key, mask ) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask) - || handleSpecialKey(key, mask); - } - } - - if( handled ) - { - resetCursorBlink(); - needsScroll(); - - if (mShowEmojiHelper) - { - // Dismiss the helper whenever we handled a key that it didn't - LLEmojiHelper::instance().hideHelper(this); - } - } - - return handled; + KEY_TAB == key) + { // Paste the first line of a tooltip into the editor + std::string message; + LLToolTipMgr::instance().getToolTipMessage(message); + LLWString tool_tip_text(utf8str_to_wstring(message)); + + if (tool_tip_text.size() > 0) + { + // Delete any selected characters (the tooltip text replaces them) + if(hasSelection()) + { + deleteSelection(TRUE); + } + + std::basic_string::size_type pos = tool_tip_text.find('\n',0); + if (pos != -1) + { // Extract the first line of the tooltip + tool_tip_text = std::basic_string(tool_tip_text, 0, pos); + } + + // Add the text + cleanStringForPaste(tool_tip_text); + pasteTextWithLinebreaks(tool_tip_text); + handled = TRUE; + } + } + else + { // Normal key handling + handled = handleNavigationKey( key, mask ) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask) + || handleSpecialKey(key, mask); + } + } + + if( handled ) + { + resetCursorBlink(); + needsScroll(); + + if (mShowEmojiHelper) + { + // Dismiss the helper whenever we handled a key that it didn't + LLEmojiHelper::instance().hideHelper(this); + } + } + + return handled; } BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } - BOOL handled = FALSE; + BOOL handled = FALSE; - // Handle most keys only if the text editor is writeable. - if( !mReadOnly ) - { + // Handle most keys only if the text editor is writeable. + if( !mReadOnly ) + { if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE)) { return TRUE; } if( mAutoIndent && '}' == uni_char ) - { - unindentLineBeforeCloseBrace(); - } + { + unindentLineBeforeCloseBrace(); + } - // TODO: KLW Add auto show of tool tip on ( - addChar( uni_char ); + // TODO: KLW Add auto show of tool tip on ( + addChar( uni_char ); - // Keys that add characters temporarily hide the cursor - getWindow()->hideCursorUntilMouseMove(); + // Keys that add characters temporarily hide the cursor + getWindow()->hideCursorUntilMouseMove(); - handled = TRUE; - } + handled = TRUE; + } - if( handled ) - { - resetCursorBlink(); + if( handled ) + { + resetCursorBlink(); - // Most keystrokes will make the selection box go away, but not all will. - deselect(); + // Most keystrokes will make the selection box go away, but not all will. + deselect(); - onKeyStroke(); - } + onKeyStroke(); + } - return handled; + return handled; } // virtual BOOL LLTextEditor::canDoDelete() const { - return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); + return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); } void LLTextEditor::doDelete() { - if( !canDoDelete() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( mCursorPos < getLength() ) - { - S32 i; - S32 chars_to_remove = 1; - LLWString text = getWText(); - if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) - { - // Try to remove a full tab's worth of spaces - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - if( chars_to_remove == 0 ) - { - chars_to_remove = SPACES_PER_TAB; - } - - for( i = 0; i < chars_to_remove; i++ ) - { - if( text[mCursorPos + i] != ' ' ) - { - chars_to_remove = 1; - break; - } - } - } - - for( i = 0; i < chars_to_remove; i++ ) - { - setCursorPos(mCursorPos + 1); - removeChar(); - } - - } - - onKeyStroke(); + if( !canDoDelete() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( mCursorPos < getLength() ) + { + S32 i; + S32 chars_to_remove = 1; + LLWString text = getWText(); + if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) + { + // Try to remove a full tab's worth of spaces + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + if( chars_to_remove == 0 ) + { + chars_to_remove = SPACES_PER_TAB; + } + + for( i = 0; i < chars_to_remove; i++ ) + { + if( text[mCursorPos + i] != ' ' ) + { + chars_to_remove = 1; + break; + } + } + } + + for( i = 0; i < chars_to_remove; i++ ) + { + setCursorPos(mCursorPos + 1); + removeChar(); + } + + } + + onKeyStroke(); } //---------------------------------------------------------------------------- @@ -2019,624 +2019,624 @@ void LLTextEditor::doDelete() void LLTextEditor::blockUndo() { - mBaseDocIsPristine = FALSE; - mLastCmd = NULL; - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); + mBaseDocIsPristine = FALSE; + mLastCmd = NULL; + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); } // virtual BOOL LLTextEditor::canUndo() const { - return !mReadOnly && mLastCmd != NULL; + return !mReadOnly && mLastCmd != NULL; } void LLTextEditor::undo() { - if( !canUndo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - pos = mLastCmd->undo(this); - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.end()) - ++iter; - if (iter != mUndoStack.end()) - mLastCmd = *iter; - else - mLastCmd = NULL; + if( !canUndo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + pos = mLastCmd->undo(this); + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.end()) + ++iter; + if (iter != mUndoStack.end()) + mLastCmd = *iter; + else + mLastCmd = NULL; - } while( mLastCmd && mLastCmd->groupWithNext() ); + } while( mLastCmd && mLastCmd->groupWithNext() ); - setCursorPos(pos); + setCursorPos(pos); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canRedo() const { - return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); + return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); } void LLTextEditor::redo() { - if( !canRedo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - if( !mLastCmd ) - { - mLastCmd = mUndoStack.back(); - } - else - { - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.begin()) - mLastCmd = *(--iter); - else - mLastCmd = NULL; - } - - if( mLastCmd ) - { - pos = mLastCmd->redo(this); - } - } while( - mLastCmd && - mLastCmd->groupWithNext() && - (mLastCmd != mUndoStack.front()) ); - - setCursorPos(pos); - - onKeyStroke(); + if( !canRedo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + if( !mLastCmd ) + { + mLastCmd = mUndoStack.back(); + } + else + { + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.begin()) + mLastCmd = *(--iter); + else + mLastCmd = NULL; + } + + if( mLastCmd ) + { + pos = mLastCmd->redo(this); + } + } while( + mLastCmd && + mLastCmd->groupWithNext() && + (mLastCmd != mUndoStack.front()) ); + + setCursorPos(pos); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() { - LLTextBase::onFocusReceived(); - updateAllowingLanguageInput(); + LLTextBase::onFocusReceived(); + updateAllowingLanguageInput(); } void LLTextEditor::focusLostHelper() { - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - if (mCommitOnFocusLost) - { - onCommit(); - } + if (mCommitOnFocusLost) + { + onCommit(); + } - // Make sure cursor is shown again - getWindow()->showCursorFromMouseMove(); + // Make sure cursor is shown again + getWindow()->showCursorFromMouseMove(); } void LLTextEditor::onFocusLost() { - focusLostHelper(); - LLTextBase::onFocusLost(); + focusLostHelper(); + LLTextBase::onFocusLost(); } void LLTextEditor::onCommit() { - setControlValue(getValue()); - LLTextBase::onCommit(); + setControlValue(getValue()); + LLTextBase::onCommit(); } void LLTextEditor::setEnabled(BOOL enabled) { - // just treat enabled as read-only flag - bool read_only = !enabled; - if (read_only != mReadOnly) - { - //mReadOnly = read_only; - LLTextBase::setReadOnly(read_only); - updateSegments(); - updateAllowingLanguageInput(); - } + // just treat enabled as read-only flag + bool read_only = !enabled; + if (read_only != mReadOnly) + { + //mReadOnly = read_only; + LLTextBase::setReadOnly(read_only); + updateSegments(); + updateAllowingLanguageInput(); + } } void LLTextEditor::showContextMenu(S32 x, S32 y) { - LLContextMenu* menu = static_cast(mContextMenuHandle.get()); - if (!menu) - { - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::createFromFile("menu_text_editor.xml", - LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if (!menu) + { + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::createFromFile("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); if(!menu) { LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL; return; } - mContextMenuHandle = menu->getHandle(); - } - - // Route menu to this class - // previously this was done in ::handleRightMoseDown: - //if(hasTabStop()) - // setFocus(TRUE) - why? weird... - // and then inside setFocus - // .... - // gEditMenuHandler = this; - // .... - // but this didn't work in all cases and just weird... - //why not here? - // (all this was done for EXT-4443) - - gEditMenuHandler = this; - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - setCursorAtLocalPos(x, y, false); - if (hasSelection()) - { - if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) - { - deselect(); - } - else - { - setCursorPos(llmax(mSelectionStart, mSelectionEnd)); - } - } - - bool use_spellcheck = getSpellCheck(), is_misspelled = false; - if (use_spellcheck) - { - mSuggestionList.clear(); - - // If the cursor is on a misspelled word, retrieve suggestions for it - std::string misspelled_word = getMisspelledWord(mCursorPos); - if ((is_misspelled = !misspelled_word.empty()) == true) - { - LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); - } - } - - menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); - menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); - menu->show(screen_x, screen_y, this); + mContextMenuHandle = menu->getHandle(); + } + + // Route menu to this class + // previously this was done in ::handleRightMoseDown: + //if(hasTabStop()) + // setFocus(TRUE) - why? weird... + // and then inside setFocus + // .... + // gEditMenuHandler = this; + // .... + // but this didn't work in all cases and just weird... + //why not here? + // (all this was done for EXT-4443) + + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } void LLTextEditor::drawPreeditMarker() { - static LLUICachedControl preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); - static LLUICachedControl preedit_marker_gap ("UIPreeditMarkerGap", 0); - static LLUICachedControl preedit_marker_position ("UIPreeditMarkerPosition", 0); - static LLUICachedControl preedit_marker_thickness ("UIPreeditMarkerThickness", 0); - static LLUICachedControl preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); - static LLUICachedControl preedit_standout_gap ("UIPreeditStandoutGap", 0); - static LLUICachedControl preedit_standout_position ("UIPreeditStandoutPosition", 0); - static LLUICachedControl preedit_standout_thickness ("UIPreeditStandoutThickness", 0); + static LLUICachedControl preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); + static LLUICachedControl preedit_marker_gap ("UIPreeditMarkerGap", 0); + static LLUICachedControl preedit_marker_position ("UIPreeditMarkerPosition", 0); + static LLUICachedControl preedit_marker_thickness ("UIPreeditMarkerThickness", 0); + static LLUICachedControl preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); + static LLUICachedControl preedit_standout_gap ("UIPreeditStandoutGap", 0); + static LLUICachedControl preedit_standout_position ("UIPreeditStandoutPosition", 0); + static LLUICachedControl preedit_standout_thickness ("UIPreeditStandoutThickness", 0); - if (!hasPreeditString()) - { - return; - } + if (!hasPreeditString()) + { + return; + } const LLWString textString(getWText()); - const llwchar *text = textString.c_str(); - const S32 text_len = getLength(); - const S32 num_lines = getLineCount(); - - S32 cur_line = getFirstVisibleLine(); - if (cur_line >= num_lines) - { - return; - } - - const S32 line_height = mFont->getLineHeight(); - - S32 line_start = getLineStart(cur_line); - S32 line_y = mVisibleTextRect.mTop - line_height; - while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) - { - S32 next_start = -1; - S32 line_end = text_len; - - if ((cur_line + 1) < num_lines) - { - next_start = getLineStart(cur_line + 1); - line_end = next_start; - } - if ( text[line_end-1] == '\n' ) - { - --line_end; - } - - // Does this line contain preedits? - if (line_start >= mPreeditPositions.back()) - { - // We have passed the preedits. - break; - } - if (line_end > mPreeditPositions.front()) - { - for (U32 i = 0; i < mPreeditStandouts.size(); i++) - { - S32 left = mPreeditPositions[i]; - S32 right = mPreeditPositions[i + 1]; - if (right <= line_start || left >= line_end) - { - continue; - } - - line_info& line = mLineInfoList[cur_line]; - LLRect text_rect(line.mRect); - text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - - S32 preedit_left = text_rect.mLeft; - if (left > line_start) - { - preedit_left += mFont->getWidth(text, line_start, left - line_start); - } - S32 preedit_right = text_rect.mLeft; - if (right < line_end) - { - preedit_right += mFont->getWidth(text, line_start, right - line_start); - } - else - { - preedit_right += mFont->getWidth(text, line_start, line_end - line_start); - } - - if (mPreeditStandouts[i]) - { - gl_rect_2d(preedit_left + preedit_standout_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_standout_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, - (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); - } - else - { - gl_rect_2d(preedit_left + preedit_marker_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_marker_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, - (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); - } - } - } - - // move down one line - line_y -= line_height; - line_start = next_start; - cur_line++; - } + const llwchar *text = textString.c_str(); + const S32 text_len = getLength(); + const S32 num_lines = getLineCount(); + + S32 cur_line = getFirstVisibleLine(); + if (cur_line >= num_lines) + { + return; + } + + const S32 line_height = mFont->getLineHeight(); + + S32 line_start = getLineStart(cur_line); + S32 line_y = mVisibleTextRect.mTop - line_height; + while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // Does this line contain preedits? + if (line_start >= mPreeditPositions.back()) + { + // We have passed the preedits. + break; + } + if (line_end > mPreeditPositions.front()) + { + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + S32 left = mPreeditPositions[i]; + S32 right = mPreeditPositions[i + 1]; + if (right <= line_start || left >= line_end) + { + continue; + } + + line_info& line = mLineInfoList[cur_line]; + LLRect text_rect(line.mRect); + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + + S32 preedit_left = text_rect.mLeft; + if (left > line_start) + { + preedit_left += mFont->getWidth(text, line_start, left - line_start); + } + S32 preedit_right = text_rect.mLeft; + if (right < line_end) + { + preedit_right += mFont->getWidth(text, line_start, right - line_start); + } + else + { + preedit_right += mFont->getWidth(text, line_start, line_end - line_start); + } + + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_left + preedit_standout_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_standout_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, + (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); + } + else + { + gl_rect_2d(preedit_left + preedit_marker_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_marker_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, + (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); + } + } + } + + // move down one line + line_y -= line_height; + line_start = next_start; + cur_line++; + } } void LLTextEditor::draw() { - { - // pad clipping rectangle so that cursor can draw at full width - // when at left edge of mVisibleTextRect - LLRect clip_rect(mVisibleTextRect); - clip_rect.stretch(1); - LLLocalClipRect clip(clip_rect); - } + { + // pad clipping rectangle so that cursor can draw at full width + // when at left edge of mVisibleTextRect + LLRect clip_rect(mVisibleTextRect); + clip_rect.stretch(1); + LLLocalClipRect clip(clip_rect); + } - LLTextBase::draw(); + LLTextBase::draw(); drawPreeditMarker(); - //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret - // when in readonly mode - mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); + //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret + // when in readonly mode + mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); } // Start or stop the editor from accepting text-editing keystrokes // see also LLLineEditor void LLTextEditor::setFocus( BOOL new_state ) { - BOOL old_state = hasFocus(); + BOOL old_state = hasFocus(); - // Don't change anything if the focus state didn't change - if (new_state == old_state) return; + // Don't change anything if the focus state didn't change + if (new_state == old_state) return; - // Notify early if we are losing focus. - if (!new_state) - { - getWindow()->allowLanguageTextInput(this, FALSE); - } + // Notify early if we are losing focus. + if (!new_state) + { + getWindow()->allowLanguageTextInput(this, FALSE); + } - LLTextBase::setFocus( new_state ); + LLTextBase::setFocus( new_state ); - if( new_state ) - { - // Route menu to this class - gEditMenuHandler = this; + if( new_state ) + { + // Route menu to this class + gEditMenuHandler = this; - // Don't start the cursor flashing right away - resetCursorBlink(); - } - else - { - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Don't start the cursor flashing right away + resetCursorBlink(); + } + else + { + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - endSelection(); - } + endSelection(); + } } // public void LLTextEditor::setCursorAndScrollToEnd() { - deselect(); - endOfDoc(); + deselect(); + endOfDoc(); } -void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) -{ - *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); - *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); +void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) +{ + *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); + *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); } void LLTextEditor::autoIndent() { - // Count the number of spaces in the current line - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); - S32 space_count = 0; - S32 i; + // Count the number of spaces in the current line + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + S32 space_count = 0; + S32 i; - LLWString text = getWText(); - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - while(( ' ' == text[line_start] ) && (space_count < offset)) - { - space_count++; - line_start++; - } + LLWString text = getWText(); + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + while(( ' ' == text[line_start] ) && (space_count < offset)) + { + space_count++; + line_start++; + } - // If we're starting a braced section, indent one level. - if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) - { - space_count += SPACES_PER_TAB; - } + // If we're starting a braced section, indent one level. + if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) + { + space_count += SPACES_PER_TAB; + } - // Insert that number of spaces on the new line + // Insert that number of spaces on the new line - //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); - addLineBreakChar(); + //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); + addLineBreakChar(); - for( i = 0; i < space_count; i++ ) - { - addChar( ' ' ); - } + for( i = 0; i < space_count; i++ ) + { + addChar( ' ' ); + } } // Inserts new text at the cursor position void LLTextEditor::insertText(const std::string &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); + + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::insertText(LLWString &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); + setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo) { - // Save old state - S32 selection_start = mSelectionStart; - S32 selection_end = mSelectionEnd; - BOOL was_selecting = mIsSelecting; - S32 cursor_pos = mCursorPos; - S32 old_length = getLength(); - BOOL cursor_was_at_end = (mCursorPos == old_length); + // Save old state + S32 selection_start = mSelectionStart; + S32 selection_end = mSelectionEnd; + BOOL was_selecting = mIsSelecting; + S32 cursor_pos = mCursorPos; + S32 old_length = getLength(); + BOOL cursor_was_at_end = (mCursorPos == old_length); - deselect(); + deselect(); - setCursorPos(old_length); + setCursorPos(old_length); - LLWString widget_wide_text = utf8str_to_wstring(text); + LLWString widget_wide_text = utf8str_to_wstring(text); - LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); - insert(getLength(), widget_wide_text, FALSE, segment); + LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); + insert(getLength(), widget_wide_text, FALSE, segment); - // Set the cursor and scroll position - if( selection_start != selection_end ) - { - mSelectionStart = selection_start; - mSelectionEnd = selection_end; + // Set the cursor and scroll position + if( selection_start != selection_end ) + { + mSelectionStart = selection_start; + mSelectionEnd = selection_end; - mIsSelecting = was_selecting; - setCursorPos(cursor_pos); - } - else if( cursor_was_at_end ) - { - setCursorPos(getLength()); - } - else - { - setCursorPos(cursor_pos); - } + mIsSelecting = was_selecting; + setCursorPos(cursor_pos); + } + else if( cursor_was_at_end ) + { + setCursorPos(getLength()); + } + else + { + setCursorPos(cursor_pos); + } - if (!allow_undo) - { - blockUndo(); - } + if (!allow_undo) + { + blockUndo(); + } } void LLTextEditor::removeTextFromEnd(S32 num_chars) { - if (num_chars <= 0) return; + if (num_chars <= 0) return; - remove(getLength() - num_chars, num_chars, FALSE); + remove(getLength() - num_chars, num_chars, FALSE); - S32 len = getLength(); - setCursorPos (llclamp(mCursorPos, 0, len)); - mSelectionStart = llclamp(mSelectionStart, 0, len); - mSelectionEnd = llclamp(mSelectionEnd, 0, len); + S32 len = getLength(); + setCursorPos (llclamp(mCursorPos, 0, len)); + mSelectionStart = llclamp(mSelectionStart, 0, len); + mSelectionEnd = llclamp(mSelectionEnd, 0, len); - needsScroll(); + needsScroll(); } //---------------------------------------------------------------------------- void LLTextEditor::onSpellCheckPerformed() { - if (isPristine()) - { - mBaseDocIsPristine = FALSE; - } + if (isPristine()) + { + mBaseDocIsPristine = FALSE; + } } void LLTextEditor::makePristine() { - mPristineCmd = mLastCmd; - mBaseDocIsPristine = !mLastCmd; + mPristineCmd = mLastCmd; + mBaseDocIsPristine = !mLastCmd; - // Create a clean partition in the undo stack. We don't want a single command to extend from - // the "pre-pristine" state to the "post-pristine" state. - if( mLastCmd ) - { - mLastCmd->blockExtensions(); - } + // Create a clean partition in the undo stack. We don't want a single command to extend from + // the "pre-pristine" state to the "post-pristine" state. + if( mLastCmd ) + { + mLastCmd->blockExtensions(); + } } BOOL LLTextEditor::isPristine() const { - if( mPristineCmd ) - { - return (mPristineCmd == mLastCmd); - } - else - { - // No undo stack, so check if the version before and commands were done was the original version - return !mLastCmd && mBaseDocIsPristine; - } + if( mPristineCmd ) + { + return (mPristineCmd == mLastCmd); + } + else + { + // No undo stack, so check if the version before and commands were done was the original version + return !mLastCmd && mBaseDocIsPristine; + } } BOOL LLTextEditor::tryToRevertToPristineState() { - if( !isPristine() ) - { - deselect(); - S32 i = 0; - while( !isPristine() && canUndo() ) - { - undo(); - i--; - } - - while( !isPristine() && canRedo() ) - { - redo(); - i++; - } - - if( !isPristine() ) - { - // failed, so go back to where we started - while( i > 0 ) - { - undo(); - i--; - } - } - } - - return isPristine(); // TRUE => success + if( !isPristine() ) + { + deselect(); + S32 i = 0; + while( !isPristine() && canUndo() ) + { + undo(); + i--; + } + + while( !isPristine() && canRedo() ) + { + redo(); + i++; + } + + if( !isPristine() ) + { + // failed, so go back to where we started + while( i > 0 ) + { + undo(); + i--; + } + } + } + + return isPristine(); // TRUE => success } void LLTextEditor::updateLinkSegments() { - LLWString wtext = getWText(); - - // update any segments that contain a link - for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegment *segment = *it; - if (segment && segment->getStyle() && segment->getStyle()->isLink()) - { - LLStyleConstSP style = segment->getStyle(); - LLStyleSP new_style(new LLStyle(*style)); - LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); - - segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); - LLTextSegment *next_segment = *next_it; - if (next_segment) - { - LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); - std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); - LLUrlMatch match; - - if ( LLUrlRegistry::instance().findUrl(link_check, match)) - { - if(match.getQuery() == wstring_to_utf8str(next_url_label)) - { - continue; - } - } - } - - // if the link's label (what the user can edit) is a valid Url, - // then update the link's HREF to be the same as the label text. - // This lets users edit Urls in-place. - if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) - { - std::string new_url = wstring_to_utf8str(url_label); - LLStringUtil::trim(new_url); - new_style->setLinkHREF(new_url); - LLStyleConstSP sp(new_style); - segment->setStyle(sp); - } - } - } + LLWString wtext = getWText(); + + // update any segments that contain a link + for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *segment = *it; + if (segment && segment->getStyle() && segment->getStyle()->isLink()) + { + LLStyleConstSP style = segment->getStyle(); + LLStyleSP new_style(new LLStyle(*style)); + LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); + + segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); + LLTextSegment *next_segment = *next_it; + if (next_segment) + { + LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); + std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); + LLUrlMatch match; + + if ( LLUrlRegistry::instance().findUrl(link_check, match)) + { + if(match.getQuery() == wstring_to_utf8str(next_url_label)) + { + continue; + } + } + } + + // if the link's label (what the user can edit) is a valid Url, + // then update the link's HREF to be the same as the label text. + // This lets users edit Urls in-place. + if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) + { + std::string new_url = wstring_to_utf8str(url_label); + LLStringUtil::trim(new_url); + new_style->setLinkHREF(new_url); + LLStyleConstSP sp(new_style); + segment->setStyle(sp); + } + } + } } void LLTextEditor::onMouseCaptureLost() { - endSelection(); + endSelection(); } /////////////////////////////////////////////////////////////////// @@ -2644,135 +2644,135 @@ void LLTextEditor::onMouseCaptureLost() BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) { - std::istringstream instream(buffer); - - // Version 1 format: - // Linden text version 1\n - // {\n - // - // Text length \n - // (text may contain ext_char_values) - // }\n - - char tbuf[MAX_STRING]; /* Flawfinder: ignore */ - - S32 version = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) - { - LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; - return FALSE; - } - - if( 1 != version ) - { - LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; - return FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( 0 != sscanf(tbuf, "{") ) - { - LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; - return FALSE; - } - - S32 text_len = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) - { - LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; - return FALSE; - } - - if( text_len > mMaxTextByteLength ) - { - LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; - return FALSE; - } - - BOOL success = TRUE; - - char* text = new char[ text_len + 1]; - if (text == NULL) - { + std::istringstream instream(buffer); + + // Version 1 format: + // Linden text version 1\n + // {\n + // + // Text length \n + // (text may contain ext_char_values) + // }\n + + char tbuf[MAX_STRING]; /* Flawfinder: ignore */ + + S32 version = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) + { + LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; + return FALSE; + } + + if( 1 != version ) + { + LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; + return FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( 0 != sscanf(tbuf, "{") ) + { + LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; + return FALSE; + } + + S32 text_len = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) + { + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; + return FALSE; + } + + if( text_len > mMaxTextByteLength ) + { + LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; + return FALSE; + } + + BOOL success = TRUE; + + char* text = new char[ text_len + 1]; + if (text == NULL) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Memory allocation failure." << LL_ENDL; - return FALSE; - } - instream.get(text, text_len + 1, '\0'); - text[text_len] = '\0'; - if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ - { - LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ - success = FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( success && (0 != sscanf(tbuf, "}")) ) - { - LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; - success = FALSE; - } - - if( success ) - { - // Actually set the text - setText( LLStringExplicit(text) ); - } - - delete[] text; - - startOfDoc(); - deselect(); - - return success; + LL_ERRS() << "Memory allocation failure." << LL_ENDL; + return FALSE; + } + instream.get(text, text_len + 1, '\0'); + text[text_len] = '\0'; + if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ + { + LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ + success = FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( success && (0 != sscanf(tbuf, "}")) ) + { + LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; + success = FALSE; + } + + if( success ) + { + // Actually set the text + setText( LLStringExplicit(text) ); + } + + delete[] text; + + startOfDoc(); + deselect(); + + return success; } BOOL LLTextEditor::exportBuffer(std::string &buffer ) { - std::ostringstream outstream(buffer); - - outstream << "Linden text version 1\n"; - outstream << "{\n"; + std::ostringstream outstream(buffer); - outstream << llformat("Text length %d\n", getLength() ); - outstream << getText(); - outstream << "}\n"; + outstream << "Linden text version 1\n"; + outstream << "{\n"; - return TRUE; + outstream << llformat("Text length %d\n", getLength() ); + outstream << getText(); + outstream << "}\n"; + + return TRUE; } void LLTextEditor::updateAllowingLanguageInput() { - LLWindow* window = getWindow(); - if (!window) - { - // test app, no window available - return; - } - if (hasFocus() && !mReadOnly) - { - window->allowLanguageTextInput(this, TRUE); - } - else - { - window->allowLanguageTextInput(this, FALSE); - } + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } + if (hasFocus() && !mReadOnly) + { + window->allowLanguageTextInput(this, TRUE); + } + else + { + window->allowLanguageTextInput(this, FALSE); + } } // Preedit is managed off the undo/redo command stack. BOOL LLTextEditor::hasPreeditString() const { - return (mPreeditPositions.size() > 1); + return (mPreeditPositions.size() > 1); } void LLTextEditor::resetPreedit() { if (hasSelection()) { - if (hasPreeditString()) + if (hasPreeditString()) { LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); @@ -2782,277 +2782,277 @@ void LLTextEditor::resetPreedit() deleteSelection(TRUE); } } - if (hasPreeditString()) - { - if (hasSelection()) - { - LL_WARNS() << "Preedit and selection!" << LL_ENDL; - deselect(); - } + if (hasPreeditString()) + { + if (hasSelection()) + { + LL_WARNS() << "Preedit and selection!" << LL_ENDL; + deselect(); + } - setCursorPos(mPreeditPositions.front()); - removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); - insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); + setCursorPos(mPreeditPositions.front()); + removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); + insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); - mPreeditWString.clear(); - mPreeditOverwrittenWString.clear(); - mPreeditPositions.clear(); + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); - // A call to updatePreedit should soon follow under a - // normal course of operation, so we don't need to - // maintain internal variables such as line start - // positions now. - } + // A call to updatePreedit should soon follow under a + // normal course of operation, so we don't need to + // maintain internal variables such as line start + // positions now. + } } void LLTextEditor::updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) { - // Just in case. - if (mReadOnly) - { - return; - } + // Just in case. + if (mReadOnly) + { + return; + } + + getWindow()->hideCursorUntilMouseMove(); - getWindow()->hideCursorUntilMouseMove(); + S32 insert_preedit_at = mCursorPos; - S32 insert_preedit_at = mCursorPos; + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; - mPreeditWString = preedit_string; - mPreeditPositions.resize(preedit_segment_lengths.size() + 1); - S32 position = insert_preedit_at; - for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) - { - mPreeditPositions[i] = position; - position += preedit_segment_lengths[i]; - } - mPreeditPositions.back() = position; + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); + removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); - removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); - } - else - { - mPreeditOverwrittenWString.clear(); - } - - segment_vec_t segments; - //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. - insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); + segment_vec_t segments; + //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. + insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); - mPreeditStandouts = preedit_standouts; + mPreeditStandouts = preedit_standouts; - setCursorPos(insert_preedit_at + caret_position); + setCursorPos(insert_preedit_at + caret_position); - // Update of the preedit should be caused by some key strokes. - resetCursorBlink(); + // Update of the preedit should be caused by some key strokes. + resetCursorBlink(); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const { - if (control) - { - LLRect control_rect_screen; - localRectToScreen(mVisibleTextRect, &control_rect_screen); - LLUI::getInstance()->screenRectToGL(control_rect_screen, control); - } - - S32 preedit_left_position, preedit_right_position; - if (hasPreeditString()) - { - preedit_left_position = mPreeditPositions.front(); - preedit_right_position = mPreeditPositions.back(); - } - else - { - preedit_left_position = preedit_right_position = mCursorPos; - } - - const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); - if (query < preedit_left_position || query > preedit_right_position) - { - return FALSE; - } - - const S32 first_visible_line = getFirstVisibleLine(); - if (query < getLineStart(first_visible_line)) - { - return FALSE; - } - - S32 current_line = first_visible_line; - S32 current_line_start, current_line_end; - for (;;) - { - current_line_start = getLineStart(current_line); - current_line_end = getLineStart(current_line + 1); - if (query >= current_line_start && query < current_line_end) - { - break; - } - if (current_line_start == current_line_end) - { - // We have reached on the last line. The query position must be here. - break; - } - current_line++; - } + if (control) + { + LLRect control_rect_screen; + localRectToScreen(mVisibleTextRect, &control_rect_screen); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_position, preedit_right_position; + if (hasPreeditString()) + { + preedit_left_position = mPreeditPositions.front(); + preedit_right_position = mPreeditPositions.back(); + } + else + { + preedit_left_position = preedit_right_position = mCursorPos; + } + + const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); + if (query < preedit_left_position || query > preedit_right_position) + { + return FALSE; + } + + const S32 first_visible_line = getFirstVisibleLine(); + if (query < getLineStart(first_visible_line)) + { + return FALSE; + } + + S32 current_line = first_visible_line; + S32 current_line_start, current_line_end; + for (;;) + { + current_line_start = getLineStart(current_line); + current_line_end = getLineStart(current_line + 1); + if (query >= current_line_start && query < current_line_end) + { + break; + } + if (current_line_start == current_line_end) + { + // We have reached on the last line. The query position must be here. + break; + } + current_line++; + } const LLWString textString(getWText()); - const llwchar * const text = textString.c_str(); - const S32 line_height = mFont->getLineHeight(); - - if (coord) - { - const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); - const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; - S32 query_screen_x, query_screen_y; - localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); - LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); - } - - if (bounds) - { - S32 preedit_left = mVisibleTextRect.mLeft; - if (preedit_left_position > current_line_start) - { - preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); - } - - S32 preedit_right = mVisibleTextRect.mLeft; - if (preedit_right_position < current_line_end) - { - preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); - } - else - { - preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); - } - - const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; - const S32 preedit_bottom = preedit_top - line_height; - - const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); - LLRect preedit_rect_screen; - localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); - } - - return TRUE; + const llwchar * const text = textString.c_str(); + const S32 line_height = mFont->getLineHeight(); + + if (coord) + { + const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; + S32 query_screen_x, query_screen_y; + localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left = mVisibleTextRect.mLeft; + if (preedit_left_position > current_line_start) + { + preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); + } + + S32 preedit_right = mVisibleTextRect.mLeft; + if (preedit_right_position < current_line_end) + { + preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); + } + else + { + preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); + } + + const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_bottom = preedit_top - line_height; + + const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; } void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const { - if (hasSelection()) - { - *position = llmin(mSelectionStart, mSelectionEnd); - *length = llabs(mSelectionStart - mSelectionEnd); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const { - if (hasPreeditString()) - { - *position = mPreeditPositions.front(); - *length = mPreeditPositions.back() - mPreeditPositions.front(); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::markAsPreedit(S32 position, S32 length) { - deselect(); - setCursorPos(position); - if (hasPreeditString()) - { - LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; - } - mPreeditWString = LLWString( getWText(), position, length ); - if (length > 0) - { - mPreeditPositions.resize(2); - mPreeditPositions[0] = position; - mPreeditPositions[1] = position + length; - mPreeditStandouts.resize(1); - mPreeditStandouts[0] = FALSE; - } - else - { - mPreeditPositions.clear(); - mPreeditStandouts.clear(); - } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = mPreeditWString; - } - else - { - mPreeditOverwrittenWString.clear(); - } + deselect(); + setCursorPos(position); + if (hasPreeditString()) + { + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; + } + mPreeditWString = LLWString( getWText(), position, length ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } } S32 LLTextEditor::getPreeditFontSize() const { - return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } BOOL LLTextEditor::isDirty() const { - if(mReadOnly) - { - return FALSE; - } + if(mReadOnly) + { + return FALSE; + } - if( mPristineCmd ) - { - return ( mPristineCmd == mLastCmd ); - } - else - { - return ( NULL != mLastCmd ); - } + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } } void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) { - mKeystrokeSignal.connect(callback); + mKeystrokeSignal.connect(callback); } void LLTextEditor::onKeyStroke() { - mKeystrokeSignal(this); + mKeystrokeSignal(this); - mSpellCheckStart = mSpellCheckEnd = -1; - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual void LLTextEditor::clear() { - getViewModel()->setDisplay(LLWStringUtil::null); - clearSegments(); + getViewModel()->setDisplay(LLWStringUtil::null); + clearSegments(); } bool LLTextEditor::canLoadOrSaveToFile() { - return !mReadOnly; + return !mReadOnly; } S32 LLTextEditor::spacesPerTab() { - return SPACES_PER_TAB; + return SPACES_PER_TAB; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 658bfb9295..2bc4184ca8 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -48,316 +48,316 @@ class LLUICtrlFactory; class LLScrollContainer; class LLTextEditor : - public LLTextBase, - protected LLPreeditor + public LLTextBase, + protected LLPreeditor { public: - struct Params : public LLInitParam::Block - { - Optional default_text; - Optional prevalidate_callback; - - Optional embedded_items, - ignore_tab, - commit_on_focus_lost, - show_context_menu, - show_emoji_helper, - enable_tooltip_paste, - auto_indent; - - //colors - Optional default_color; - - Params(); - }; - - void initFromParams(const Params&); + struct Params : public LLInitParam::Block + { + Optional default_text; + Optional prevalidate_callback; + + Optional embedded_items, + ignore_tab, + commit_on_focus_lost, + show_context_menu, + show_emoji_helper, + enable_tooltip_paste, + auto_indent; + + //colors + Optional default_color; + + Params(); + }; + + void initFromParams(const Params&); protected: - LLTextEditor(const Params&); - friend class LLUICtrlFactory; + LLTextEditor(const Params&); + friend class LLUICtrlFactory; public: - // - // Constants - // - static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; - static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; - static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; + // + // Constants + // + static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; + static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; + static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; - virtual ~LLTextEditor(); + virtual ~LLTextEditor(); - typedef boost::signals2::signal keystroke_signal_t; + typedef boost::signals2::signal keystroke_signal_t; - void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); - void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} - static S32 spacesPerTab(); + static S32 spacesPerTab(); - void insertEmoji(llwchar emoji); - void handleEmojiCommit(llwchar emoji); + void insertEmoji(llwchar emoji); + void handleEmojiCommit(llwchar emoji); - // mousehandler overrides - 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 handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); - virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + // mousehandler overrides + 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 handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); + virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask ); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleKeyHere(KEY key, MASK mask ); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void onMouseCaptureLost(); + virtual void onMouseCaptureLost(); - // view overrides - virtual void draw(); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual void onCommit(); - virtual void setEnabled(BOOL enabled); + // view overrides + virtual void draw(); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual void onCommit(); + virtual void setEnabled(BOOL enabled); - // uictrl overrides - virtual void clear(); - virtual void setFocus( BOOL b ); - virtual BOOL isDirty() const; + // uictrl overrides + virtual void clear(); + virtual void setFocus( BOOL b ); + virtual BOOL isDirty() const; - // LLEditMenuHandler interface - virtual void undo(); - virtual BOOL canUndo() const; - virtual void redo(); - virtual BOOL canRedo() const; + // LLEditMenuHandler interface + virtual void undo(); + virtual BOOL canUndo() const; + virtual void redo(); + virtual BOOL canRedo() const; - virtual void cut(); - virtual BOOL canCut() const; - virtual void copy(); - virtual BOOL canCopy() const; - virtual void paste(); - virtual BOOL canPaste() const; + virtual void cut(); + virtual BOOL canCut() const; + virtual void copy(); + virtual BOOL canCopy() const; + virtual void paste(); + virtual BOOL canPaste() const; - virtual void updatePrimary(); - virtual void copyPrimary(); - virtual void pastePrimary(); - virtual BOOL canPastePrimary() const; + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; - virtual void doDelete(); - virtual BOOL canDoDelete() const; - virtual void selectAll(); - virtual BOOL canSelectAll() const; + virtual void doDelete(); + virtual BOOL canDoDelete() const; + virtual void selectAll(); + virtual BOOL canSelectAll() const; - void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); - virtual bool canLoadOrSaveToFile(); + virtual bool canLoadOrSaveToFile(); - void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); - BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); - void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); + void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); + BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); + void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); - // Undo/redo stack - void blockUndo(); + // Undo/redo stack + void blockUndo(); - // Text editing - virtual void makePristine(); - BOOL isPristine() const; - BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } + // Text editing + virtual void makePristine(); + BOOL isPristine() const; + BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } - // Autoreplace (formerly part of LLLineEditor) - typedef boost::function autoreplace_callback_t; - autoreplace_callback_t mAutoreplaceCallback; - void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } + // Autoreplace (formerly part of LLLineEditor) + typedef boost::function autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } - /*virtual*/ void onSpellCheckPerformed(); + /*virtual*/ void onSpellCheckPerformed(); - // - // Text manipulation - // + // + // Text manipulation + // - // inserts text at cursor - void insertText(const std::string &text); - void insertText(LLWString &text); + // inserts text at cursor + void insertText(const std::string &text); + void insertText(LLWString &text); - void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); - // Non-undoable - void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); + void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); + // Non-undoable + void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); - // Removes text from the end of document - // Does not change highlight or cursor position. - void removeTextFromEnd(S32 num_chars); + // Removes text from the end of document + // Does not change highlight or cursor position. + void removeTextFromEnd(S32 num_chars); - BOOL tryToRevertToPristineState(); + BOOL tryToRevertToPristineState(); - void setCursorAndScrollToEnd(); + void setCursorAndScrollToEnd(); - void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); + void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); - // Hacky methods to make it into a word-wrapping, potentially scrolling, - // read-only text box. - void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } + // Hacky methods to make it into a word-wrapping, potentially scrolling, + // read-only text box. + void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } - // Hack to handle Notecards - virtual BOOL importBuffer(const char* buffer, S32 length ); - virtual BOOL exportBuffer(std::string& buffer ); + // Hack to handle Notecards + virtual BOOL importBuffer(const char* buffer, S32 length ); + virtual BOOL exportBuffer(std::string& buffer ); - const LLUUID& getSourceID() const { return mSourceID; } + const LLUUID& getSourceID() const { return mSourceID; } - const LLTextSegmentPtr getPreviousSegment() const; - const LLTextSegmentPtr getLastSegment() const; - void getSelectedSegments(segment_vec_t& segments) const; + const LLTextSegmentPtr getPreviousSegment() const; + const LLTextSegmentPtr getLastSegment() const; + void getSelectedSegments(segment_vec_t& segments) const; - void setShowContextMenu(bool show) { mShowContextMenu = show; } - bool getShowContextMenu() const { return mShowContextMenu; } + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getShowContextMenu() const { return mShowContextMenu; } - void showEmojiHelper(); - void setShowEmojiHelper(bool show); - bool getShowEmojiHelper() const { return mShowEmojiHelper; } + void showEmojiHelper(); + void setShowEmojiHelper(bool show); + bool getShowEmojiHelper() const { return mShowEmojiHelper; } - void setPassDelete(BOOL b) { mPassDelete = b; } + void setPassDelete(BOOL b) { mPassDelete = b; } protected: - void showContextMenu(S32 x, S32 y); - void drawPreeditMarker(); + void showContextMenu(S32 x, S32 y); + void drawPreeditMarker(); - void assignEmbedded(const std::string &s); + void assignEmbedded(const std::string &s); - void removeCharOrTab(); + void removeCharOrTab(); - void indentSelectedLines( S32 spaces ); - S32 indentLine( S32 pos, S32 spaces ); - void unindentLineBeforeCloseBrace(); + void indentSelectedLines( S32 spaces ); + S32 indentLine( S32 pos, S32 spaces ); + void unindentLineBeforeCloseBrace(); - virtual BOOL handleSpecialKey(const KEY key, const MASK mask); - BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSelectionKey(const KEY key, const MASK mask); - BOOL handleControlKey(const KEY key, const MASK mask); + virtual BOOL handleSpecialKey(const KEY key, const MASK mask); + BOOL handleNavigationKey(const KEY key, const MASK mask); + BOOL handleSelectionKey(const KEY key, const MASK mask); + BOOL handleControlKey(const KEY key, const MASK mask); - BOOL selectionContainsLineBreaks(); - void deleteSelection(BOOL transient_operation); + BOOL selectionContainsLineBreaks(); + void deleteSelection(BOOL transient_operation); - S32 prevWordPos(S32 cursorPos) const; - S32 nextWordPos(S32 cursorPos) const; + S32 prevWordPos(S32 cursorPos) const; + S32 nextWordPos(S32 cursorPos) const; - void autoIndent(); + void autoIndent(); - void findEmbeddedItemSegments(S32 start, S32 end); - void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; + void findEmbeddedItemSegments(S32 start, S32 end); + void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; - virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } + virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } - // Here's the method that takes and applies text commands. - S32 execute(TextCmd* cmd); + // Here's the method that takes and applies text commands. + S32 execute(TextCmd* cmd); - // Undoable operations - void addChar(llwchar c); // at mCursorPos - S32 addChar(S32 pos, llwchar wc); + // Undoable operations + void addChar(llwchar c); // at mCursorPos + S32 addChar(S32 pos, llwchar wc); public: - void addLineBreakChar(BOOL group_together = FALSE); + void addLineBreakChar(BOOL group_together = FALSE); protected: - S32 overwriteChar(S32 pos, llwchar wc); - void removeChar(); - S32 removeChar(S32 pos); - S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); - S32 remove(S32 pos, S32 length, bool group_with_next_op); - - void tryToShowEmojiHelper(); - void focusLostHelper(); - void updateAllowingLanguageInput(); - BOOL hasPreeditString() const; - - // Overrides LLPreeditor - virtual void resetPreedit(); - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); - virtual void markAsPreedit(S32 position, S32 length); - virtual void getPreeditRange(S32 *position, S32 *length) const; - virtual void getSelectionRange(S32 *position, S32 *length) const; - virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; - virtual S32 getPreeditFontSize() const; - virtual LLWString getPreeditString() const { return getWText(); } - // - // Protected data - // - // Probably deserves serious thought to hiding as many of these - // as possible behind protected accessor methods. - // - - // Use these to determine if a click on an embedded item is a drag or not. - S32 mMouseDownX; - S32 mMouseDownY; - - LLWString mPreeditWString; - LLWString mPreeditOverwrittenWString; - std::vector mPreeditPositions; - std::vector mPreeditStandouts; + S32 overwriteChar(S32 pos, llwchar wc); + void removeChar(); + S32 removeChar(S32 pos); + S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); + S32 remove(S32 pos, S32 length, bool group_with_next_op); + + void tryToShowEmojiHelper(); + void focusLostHelper(); + void updateAllowingLanguageInput(); + BOOL hasPreeditString() const; + + // Overrides LLPreeditor + virtual void resetPreedit(); + virtual void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); + virtual void markAsPreedit(S32 position, S32 length); + virtual void getPreeditRange(S32 *position, S32 *length) const; + virtual void getSelectionRange(S32 *position, S32 *length) const; + virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; + virtual S32 getPreeditFontSize() const; + virtual LLWString getPreeditString() const { return getWText(); } + // + // Protected data + // + // Probably deserves serious thought to hiding as many of these + // as possible behind protected accessor methods. + // + + // Use these to determine if a click on an embedded item is a drag or not. + S32 mMouseDownX; + S32 mMouseDownY; + + LLWString mPreeditWString; + LLWString mPreeditOverwrittenWString; + std::vector mPreeditPositions; + std::vector mPreeditStandouts; protected: - LLUIColor mDefaultColor; + LLUIColor mDefaultColor; - bool mAutoIndent; - bool mParseOnTheFly; + bool mAutoIndent; + bool mParseOnTheFly; - void updateLinkSegments(); - void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } - class LLViewBorder* mBorder; + void updateLinkSegments(); + void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } + class LLViewBorder* mBorder; private: - // - // Methods - // - void pasteHelper(bool is_primary); - void cleanStringForPaste(LLWString & clean_string); + // + // Methods + // + void pasteHelper(bool is_primary); + void cleanStringForPaste(LLWString & clean_string); public: - template - void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) - { - pasteTextWithLinebreaks(ll_convert(clean_string)); - } - template <> - void pasteTextWithLinebreaks(const LLWString & clean_string); + template + void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) + { + pasteTextWithLinebreaks(ll_convert(clean_string)); + } + template <> + void pasteTextWithLinebreaks(const LLWString & clean_string); private: - void onKeyStroke(); + void onKeyStroke(); - // Concrete TextCmd sub-classes used by the LLTextEditor base class - class TextCmdInsert; - class TextCmdAddChar; - class TextCmdOverwriteChar; - class TextCmdRemove; + // Concrete TextCmd sub-classes used by the LLTextEditor base class + class TextCmdInsert; + class TextCmdAddChar; + class TextCmdOverwriteChar; + class TextCmdRemove; - BOOL mBaseDocIsPristine; - TextCmd* mPristineCmd; + BOOL mBaseDocIsPristine; + TextCmd* mPristineCmd; - TextCmd* mLastCmd; + TextCmd* mLastCmd; - typedef std::deque undo_stack_t; - undo_stack_t mUndoStack; + typedef std::deque undo_stack_t; + undo_stack_t mUndoStack; - BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces - BOOL mCommitOnFocusLost; - BOOL mTakesFocus; + BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces + BOOL mCommitOnFocusLost; + BOOL mTakesFocus; - BOOL mAllowEmbeddedItems; - bool mShowContextMenu; - bool mShowEmojiHelper; - bool mEnableTooltipPaste; - bool mPassDelete; - bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + BOOL mAllowEmbeddedItems; + bool mShowContextMenu; + bool mShowEmojiHelper; + bool mEnableTooltipPaste; + bool mPassDelete; + bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter - LLUUID mSourceID; + LLUUID mSourceID; - LLCoordGL mLastIMEPosition; // Last position of the IME editor + LLCoordGL mLastIMEPosition; // Last position of the IME editor - keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + keystroke_signal_t mKeystrokeSignal; + LLTextValidate::validate_func_t mPrevalidateFunc; - LLHandle mContextMenuHandle; + LLHandle mContextMenuHandle; }; // end class LLTextEditor // Build time optimization, generate once in .cpp file #ifndef LLTEXTEDITOR_CPP extern template class LLTextEditor* LLView::getChild( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_TEXTEDITOR_H diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 9e9e424455..613f57dbf1 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -1,25 +1,25 @@ -/** +/** * @file llwindow.h * @brief Basic graphical window class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,40 +44,40 @@ class LLWindow : public LLInstanceTracker { public: - struct LLWindowResolution - { - S32 mWidth; - S32 mHeight; - }; - enum ESwapMethod - { - SWAP_METHOD_UNDEFINED, - SWAP_METHOD_EXCHANGE, - SWAP_METHOD_COPY - }; - enum EFlags - { - // currently unused - }; + struct LLWindowResolution + { + S32 mWidth; + S32 mHeight; + }; + enum ESwapMethod + { + SWAP_METHOD_UNDEFINED, + SWAP_METHOD_EXCHANGE, + SWAP_METHOD_COPY + }; + enum EFlags + { + // currently unused + }; public: - virtual void show() = 0; - virtual void hide() = 0; - virtual void close() = 0; - virtual BOOL getVisible() = 0; - virtual BOOL getMinimized() = 0; - virtual BOOL getMaximized() = 0; - virtual BOOL maximize() = 0; - virtual void minimize() = 0; - virtual void restore() = 0; - BOOL getFullscreen() { return mFullscreen; }; - virtual BOOL getPosition(LLCoordScreen *position) = 0; - virtual BOOL getSize(LLCoordScreen *size) = 0; - virtual BOOL getSize(LLCoordWindow *size) = 0; - virtual BOOL setPosition(LLCoordScreen position) = 0; - BOOL setSize(LLCoordScreen size); - BOOL setSize(LLCoordWindow size); - virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0; + virtual void show() = 0; + virtual void hide() = 0; + virtual void close() = 0; + virtual BOOL getVisible() = 0; + virtual BOOL getMinimized() = 0; + virtual BOOL getMaximized() = 0; + virtual BOOL maximize() = 0; + virtual void minimize() = 0; + virtual void restore() = 0; + BOOL getFullscreen() { return mFullscreen; }; + virtual BOOL getPosition(LLCoordScreen *position) = 0; + virtual BOOL getSize(LLCoordScreen *size) = 0; + virtual BOOL getSize(LLCoordWindow *size) = 0; + virtual BOOL setPosition(LLCoordScreen position) = 0; + BOOL setSize(LLCoordScreen size); + BOOL setSize(LLCoordWindow size); + virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); + virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0; //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread // returns a pointer to be handed back to destroySharedConext/makeContextCurrent @@ -91,113 +91,113 @@ public: virtual void toggleVSync(bool enable_vsync) = 0; virtual BOOL setCursorPosition(LLCoordWindow position) = 0; - virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; + virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; #if LL_WINDOWS virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0; #endif - virtual void showCursor() = 0; - virtual void hideCursor() = 0; - virtual BOOL isCursorHidden() = 0; - virtual void showCursorFromMouseMove() = 0; - virtual void hideCursorUntilMouseMove() = 0; + virtual void showCursor() = 0; + virtual void hideCursor() = 0; + virtual BOOL isCursorHidden() = 0; + virtual void showCursorFromMouseMove() = 0; + virtual void hideCursorUntilMouseMove() = 0; // Provide a way to set the Viewer window title after the // windows has been created. The initial use case for this - // is described in SL-16102 (update window title with agent + // is described in SL-16102 (update window title with agent // name, location etc. for non-interactive viewer) but it // may also be useful in other cases. virtual void setTitle(const std::string title); - // These two functions create a way to make a busy cursor instead - // of an arrow when someone's busy doing something. Draw an - // arrow/hour if busycount > 0. - virtual void incBusyCount(); - virtual void decBusyCount(); - virtual void resetBusyCount(); - virtual S32 getBusyCount() const; + // These two functions create a way to make a busy cursor instead + // of an arrow when someone's busy doing something. Draw an + // arrow/hour if busycount > 0. + virtual void incBusyCount(); + virtual void decBusyCount(); + virtual void resetBusyCount(); + virtual S32 getBusyCount() const; - // Sets cursor, may set to arrow+hourglass - virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; }; + // Sets cursor, may set to arrow+hourglass + virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; }; virtual ECursorType getCursor() const; virtual ECursorType getNextCursor() const { return mNextCursor; }; - virtual void updateCursor() = 0; - - virtual void captureMouse() = 0; - virtual void releaseMouse() = 0; - virtual void setMouseClipping( BOOL b ) = 0; - - virtual BOOL isClipboardTextAvailable() = 0; - virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; - virtual BOOL copyTextToClipboard(const LLWString &src) = 0; - - virtual BOOL isPrimaryTextAvailable(); - virtual BOOL pasteTextFromPrimary(LLWString &dst); - virtual BOOL copyTextToPrimary(const LLWString &src); - - virtual void flashIcon(F32 seconds) = 0; - virtual F32 getGamma() = 0; - virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma - virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples - virtual U32 getFSAASamples() = 0; - virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) - virtual ESwapMethod getSwapMethod() { return mSwapMethod; } - virtual void processMiscNativeEvents(); - virtual void gatherInput() = 0; - virtual void delayInputProcessing() = 0; - virtual void swapBuffers() = 0; - virtual void bringToFront() = 0; - virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract - virtual void setOldResize(bool oldresize) { }; - // handy coordinate space conversion routines - // NB: screen to window and vice verse won't work on width/height coordinate pairs, - // as the conversion must take into account left AND right border widths, etc. - virtual BOOL convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; - virtual BOOL convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; - virtual BOOL convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; - virtual BOOL convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; - virtual BOOL convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; - virtual BOOL convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; - - // query supported resolutions - virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; - virtual F32 getNativeAspectRatio() = 0; - virtual F32 getPixelAspectRatio() = 0; - virtual void setNativeAspectRatio(F32 aspect) = 0; - - // query VRAM usage - virtual U32 getAvailableVRAMMegabytes() = 0; - - virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) - virtual void afterDialog() {}; // undo whatever was done in beforeDialog() - - // opens system default color picker, modally - // Returns TRUE if valid color selected - virtual BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); + virtual void updateCursor() = 0; + + virtual void captureMouse() = 0; + virtual void releaseMouse() = 0; + virtual void setMouseClipping( BOOL b ) = 0; + + virtual BOOL isClipboardTextAvailable() = 0; + virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; + virtual BOOL copyTextToClipboard(const LLWString &src) = 0; + + virtual BOOL isPrimaryTextAvailable(); + virtual BOOL pasteTextFromPrimary(LLWString &dst); + virtual BOOL copyTextToPrimary(const LLWString &src); + + virtual void flashIcon(F32 seconds) = 0; + virtual F32 getGamma() = 0; + virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma + virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples + virtual U32 getFSAASamples() = 0; + virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) + virtual ESwapMethod getSwapMethod() { return mSwapMethod; } + virtual void processMiscNativeEvents(); + virtual void gatherInput() = 0; + virtual void delayInputProcessing() = 0; + virtual void swapBuffers() = 0; + virtual void bringToFront() = 0; + virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract + virtual void setOldResize(bool oldresize) { }; + // handy coordinate space conversion routines + // NB: screen to window and vice verse won't work on width/height coordinate pairs, + // as the conversion must take into account left AND right border widths, etc. + virtual BOOL convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; + virtual BOOL convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; + virtual BOOL convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; + virtual BOOL convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; + virtual BOOL convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; + virtual BOOL convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; + + // query supported resolutions + virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; + virtual F32 getNativeAspectRatio() = 0; + virtual F32 getPixelAspectRatio() = 0; + virtual void setNativeAspectRatio(F32 aspect) = 0; + + // query VRAM usage + virtual U32 getAvailableVRAMMegabytes() = 0; + + virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) + virtual void afterDialog() {}; // undo whatever was done in beforeDialog() + + // opens system default color picker, modally + // Returns TRUE if valid color selected + virtual BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getPlatformWindow() = 0; + virtual void *getPlatformWindow() = 0; // return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getMediaWindow(); - - // control platform's Language Text Input mechanisms. - virtual void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) {} - virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; - virtual void updateLanguageTextInputArea() {} - virtual void interruptLanguageTextInput() {} - virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; + virtual void *getMediaWindow(); + + // control platform's Language Text Input mechanisms. + virtual void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) {} + virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; + virtual void updateLanguageTextInputArea() {} + virtual void interruptLanguageTextInput() {} + virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; virtual void openFolder(const std::string &path) {}; - static std::vector getDynamicFallbackFontList(); - - // Provide native key event data - virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } + static std::vector getDynamicFallbackFontList(); + + // Provide native key event data + virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } - // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) - virtual F32 getSystemUISize() { return 1.0; } + // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) + virtual F32 getSystemUISize() { return 1.0; } - static std::vector getDisplaysResolutionList(); + static std::vector getDisplaysResolutionList(); // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; @@ -205,49 +205,49 @@ public: virtual S32 getRefreshRate() { return mRefreshRate; } protected: - LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); - virtual ~LLWindow(); - // Defaults to true - virtual BOOL isValid(); - // Defaults to true - virtual BOOL canDelete(); + LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); + virtual ~LLWindow(); + // Defaults to true + virtual BOOL isValid(); + // Defaults to true + virtual BOOL canDelete(); - virtual BOOL setSizeImpl(LLCoordScreen size) = 0; - virtual BOOL setSizeImpl(LLCoordWindow size) = 0; + virtual BOOL setSizeImpl(LLCoordScreen size) = 0; + virtual BOOL setSizeImpl(LLCoordWindow size) = 0; protected: - LLWindowCallbacks* mCallbacks; - - BOOL mPostQuit; // should this window post a quit message when destroyed? - BOOL mFullscreen; - S32 mFullscreenWidth; - S32 mFullscreenHeight; - S32 mFullscreenBits; - S32 mFullscreenRefresh; - LLWindowResolution* mSupportedResolutions; - S32 mNumSupportedResolutions; - ECursorType mCurrentCursor; - ECursorType mNextCursor; - BOOL mCursorHidden; - S32 mBusyCount; // how deep is the "cursor busy" stack? - BOOL mIsMouseClipping; // Is this window currently clipping the mouse - ESwapMethod mSwapMethod; - BOOL mHideCursorPermanent; - U32 mFlags; - U16 mHighSurrogate; - S32 mMinWindowWidth; - S32 mMinWindowHeight; + LLWindowCallbacks* mCallbacks; + + BOOL mPostQuit; // should this window post a quit message when destroyed? + BOOL mFullscreen; + S32 mFullscreenWidth; + S32 mFullscreenHeight; + S32 mFullscreenBits; + S32 mFullscreenRefresh; + LLWindowResolution* mSupportedResolutions; + S32 mNumSupportedResolutions; + ECursorType mCurrentCursor; + ECursorType mNextCursor; + BOOL mCursorHidden; + S32 mBusyCount; // how deep is the "cursor busy" stack? + BOOL mIsMouseClipping; // Is this window currently clipping the mouse + ESwapMethod mSwapMethod; + BOOL mHideCursorPermanent; + U32 mFlags; + U16 mHighSurrogate; + S32 mMinWindowWidth; + S32 mMinWindowHeight; S32 mRefreshRate; - // Handle a UTF-16 encoding unit received from keyboard. - // Converting the series of UTF-16 encoding units to UTF-32 data, - // this method passes the resulting UTF-32 data to mCallback's - // handleUnicodeChar. The mask should be that to be passed to the - // callback. This method uses mHighSurrogate as a dedicated work - // variable. - void handleUnicodeUTF16(U16 utf16, MASK mask); + // Handle a UTF-16 encoding unit received from keyboard. + // Converting the series of UTF-16 encoding units to UTF-32 data, + // this method passes the resulting UTF-32 data to mCallback's + // handleUnicodeChar. The mask should be that to be passed to the + // callback. This method uses mHighSurrogate as a dedicated work + // variable. + void handleUnicodeUTF16(U16 utf16, MASK mask); - friend class LLWindowManager; + friend class LLWindowManager; }; @@ -260,24 +260,24 @@ protected: class LLSplashScreen { public: - LLSplashScreen() { }; - virtual ~LLSplashScreen() { }; + LLSplashScreen() { }; + virtual ~LLSplashScreen() { }; - // Call to display the window. - static LLSplashScreen * create(); - static void show(); - static void hide(); - static void update(const std::string& string); + // Call to display the window. + static LLSplashScreen * create(); + static void show(); + static void hide(); + static void update(const std::string& string); - static bool isVisible(); + static bool isVisible(); protected: - // These are overridden by the platform implementation - virtual void showImpl() = 0; - virtual void updateImpl(const std::string& string) = 0; - virtual void hideImpl() = 0; + // These are overridden by the platform implementation + virtual void showImpl() = 0; + virtual void updateImpl(const std::string& string) = 0; + virtual void hideImpl() = 0; - static BOOL sVisible; + static BOOL sVisible; }; @@ -299,21 +299,21 @@ const S32 OSBTN_CANCEL = 3; class LLWindowManager { public: - static LLWindow *createWindow( - LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - U32 flags = 0, - BOOL fullscreen = FALSE, - BOOL clearBg = FALSE, - BOOL enable_vsync = FALSE, - BOOL use_gl = TRUE, - BOOL ignore_pixel_depth = FALSE, - U32 fsaa_samples = 0, + static LLWindow *createWindow( + LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, + U32 flags = 0, + BOOL fullscreen = FALSE, + BOOL clearBg = FALSE, + BOOL enable_vsync = FALSE, + BOOL use_gl = TRUE, + BOOL ignore_pixel_depth = FALSE, + U32 fsaa_samples = 0, U32 max_cores = 0, U32 max_vram = 0, F32 max_gl_version = 4.6f); - static BOOL destroyWindow(LLWindow* window); - static BOOL isWindowValid(LLWindow *window); + static BOOL destroyWindow(LLWindow* window); + static BOOL isWindowValid(LLWindow *window); }; // diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index ade303c6d4..80ecd1d040 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -1,4 +1,4 @@ -/** +/** * @file llwindowmacosx-objc.h * @brief Prototypes for functions shared between llwindowmacosx.cpp * and llwindowmacosx-objc.mm. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,8 +40,8 @@ typedef std::vector segment_lengths; typedef std::vector segment_standouts; struct attributedStringInfo { - segment_lengths seg_lengths; - segment_standouts seg_standouts; + segment_lengths seg_lengths; + segment_standouts seg_standouts; }; // This will actually hold an NSCursor*, but that type is only available in objective C. @@ -57,7 +57,7 @@ struct NativeKeyEventData { KEYDOWN, KEYCHAR }; - + EventType mKeyEvent = KEYUNKNOWN; uint32_t mEventType = 0; uint32_t mEventModifiers = 0; diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index b774597eb6..0d9b491272 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -46,8 +46,8 @@ extern BOOL gDebugWindowProc; BOOL gHiDPISupport = TRUE; -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; const S32 DEFAULT_REFRESH_RATE = 60; @@ -65,34 +65,34 @@ BOOL LLWindowMacOSX::sUseMultGL = FALSE; BOOL check_for_card(const char* RENDERER, const char* bad_card) { - if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) - { - std::string buffer = llformat( - "Your video card appears to be a %s, which Second Life does not support.\n" - "\n" - "Second Life requires a video card with 32 Mb of memory or more, as well as\n" - "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" - "and ATI Radeon 8500 or better.\n" - "\n" - "If you own a supported card and continue to receive this message, try \n" - "updating to the latest video card drivers. Otherwise look in the\n" - "secondlife.com support section or e-mail technical support\n" - "\n" - "You can try to run Second Life, but it will probably crash or run\n" - "very slowly. Try anyway?", - bad_card); - S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); - if (OSBTN_YES == button) - { - return FALSE; - } - else - { - return TRUE; - } - } - - return FALSE; + if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) + { + std::string buffer = llformat( + "Your video card appears to be a %s, which Second Life does not support.\n" + "\n" + "Second Life requires a video card with 32 Mb of memory or more, as well as\n" + "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" + "and ATI Radeon 8500 or better.\n" + "\n" + "If you own a supported card and continue to receive this message, try \n" + "updating to the latest video card drivers. Otherwise look in the\n" + "secondlife.com support section or e-mail technical support\n" + "\n" + "You can try to run Second Life, but it will probably crash or run\n" + "very slowly. Try anyway?", + bad_card); + S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); + if (OSBTN_YES == button) + { + return FALSE; + } + else + { + return TRUE; + } + } + + return FALSE; } // Switch to determine whether we capture all displays, or just the main one. @@ -110,93 +110,93 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key); static LLWindowMacOSX *gWindowImplementation = NULL; LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, - U32 fsaa_samples) - : LLWindow(NULL, fullscreen, flags) -{ - // *HACK: During window construction we get lots of OS events for window - // reshape, activate, etc. that the viewer isn't ready to handle. - // Route them to a dummy callback structure until the end of constructor. - LLWindowCallbacks null_callbacks; - mCallbacks = &null_callbacks; - - // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). - setupCocoa(); - - // Initialize the keyboard - gKeyboard = new LLKeyboardMacOSX(); - gKeyboard->setCallbacks(callbacks); - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mContext = NULL; - mPixelFormat = NULL; - mDisplay = CGMainDisplayID(); - mSimulatedRightClick = FALSE; - mLastModifiers = 0; - mHandsOffEvents = FALSE; - mCursorDecoupled = FALSE; - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - mNeedsResize = FALSE; - mOverrideAspectRatio = 0.f; - mMaximized = FALSE; - mMinimized = FALSE; - mLanguageTextInputAllowed = FALSE; - mPreeditor = NULL; - mFSAASamples = fsaa_samples; - mForceRebuild = FALSE; - - // Get the original aspect ratio of the main device. - mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); - - // Stash the window title - mWindowTitle = title; - //mWindowTitle[0] = title.length(); - - mDragOverrideCursor = -1; - - // Set up global event handlers (the fullscreen case needs this) - //InstallStandardEventHandler(GetApplicationEventTarget()); - - // Stash an object pointer for OSMessageBox() - gWindowImplementation = this; - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) - { - if(mWindow != NULL) - { - makeWindowOrderFront(mWindow); - } - - if (!gGLManager.initGL()) - { - setupFailure( - "Second Life is unable to run because your video card drivers\n" - "are out of date or unsupported. Please make sure you have\n" - "the latest video card drivers installed.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + BOOL fullscreen, BOOL clearBg, + BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, + U32 fsaa_samples) + : LLWindow(NULL, fullscreen, flags) +{ + // *HACK: During window construction we get lots of OS events for window + // reshape, activate, etc. that the viewer isn't ready to handle. + // Route them to a dummy callback structure until the end of constructor. + LLWindowCallbacks null_callbacks; + mCallbacks = &null_callbacks; + + // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). + setupCocoa(); + + // Initialize the keyboard + gKeyboard = new LLKeyboardMacOSX(); + gKeyboard->setCallbacks(callbacks); + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mContext = NULL; + mPixelFormat = NULL; + mDisplay = CGMainDisplayID(); + mSimulatedRightClick = FALSE; + mLastModifiers = 0; + mHandsOffEvents = FALSE; + mCursorDecoupled = FALSE; + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = FALSE; + mNeedsResize = FALSE; + mOverrideAspectRatio = 0.f; + mMaximized = FALSE; + mMinimized = FALSE; + mLanguageTextInputAllowed = FALSE; + mPreeditor = NULL; + mFSAASamples = fsaa_samples; + mForceRebuild = FALSE; + + // Get the original aspect ratio of the main device. + mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); + + // Stash the window title + mWindowTitle = title; + //mWindowTitle[0] = title.length(); + + mDragOverrideCursor = -1; + + // Set up global event handlers (the fullscreen case needs this) + //InstallStandardEventHandler(GetApplicationEventTarget()); + + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) + { + if(mWindow != NULL) + { + makeWindowOrderFront(mWindow); + } + + if (!gGLManager.initGL()) + { + setupFailure( + "Second Life is unable to run because your video card drivers\n" + "are out of date or unsupported. Please make sure you have\n" + "the latest video card drivers installed.\n" + "If you continue to receive this message, contact customer service.", + "Error", + OSMB_OK); + return; + } //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - - allowLanguageTextInput(NULL, FALSE); - } + initCursors(); + setCursor( UI_CURSOR_ARROW ); + + allowLanguageTextInput(NULL, FALSE); + } + + mCallbacks = callbacks; + stop_glerror(); + - mCallbacks = callbacks; - stop_glerror(); - - } // These functions are used as wrappers for our internal event handling callbacks. @@ -205,7 +205,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) { mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyUp(key, mask); + bool retVal = gKeyboard->handleKeyUp(key, mask); mRawKeyEvent = NULL; return retVal; } @@ -222,22 +222,22 @@ bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wch } mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyDown(key, mask); + bool retVal = gKeyboard->handleKeyDown(key, mask); mRawKeyEvent = NULL; return retVal; } void callResetKeys() { - gKeyboard->resetKeys(); + gKeyboard->resetKeys(); } bool callUnicodeCallback(wchar_t character, unsigned int mask) { NativeKeyEventData eventData; - + memset(&eventData, 0, sizeof(NativeKeyEventData)); - + eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; eventData.mEventType = 0; eventData.mEventModifiers = mask; @@ -245,9 +245,9 @@ bool callUnicodeCallback(wchar_t character, unsigned int mask) eventData.mEventChars = character; eventData.mEventUnmodChars = character; eventData.mEventRepeat = false; - + mRawKeyEvent = &eventData; - + bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); mRawKeyEvent = NULL; return result; @@ -255,18 +255,18 @@ bool callUnicodeCallback(wchar_t character, unsigned int mask) void callFocus() { - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); - } + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); + } } void callFocusLost() { - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } } void callRightMouseDown(float *pos, MASK mask) @@ -275,11 +275,11 @@ void callRightMouseDown(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callRightMouseUp(float *pos, MASK mask) @@ -288,11 +288,11 @@ void callRightMouseUp(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callLeftMouseDown(float *pos, MASK mask) @@ -301,11 +301,11 @@ void callLeftMouseDown(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callLeftMouseUp(float *pos, MASK mask) @@ -314,12 +314,12 @@ void callLeftMouseUp(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); - + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + } void callDoubleClick(float *pos, MASK mask) @@ -328,37 +328,37 @@ void callDoubleClick(float *pos, MASK mask) { gWindowImplementation->interruptLanguageTextInput(); } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } void callResize(unsigned int width, unsigned int height) { - if (gWindowImplementation != NULL) - { - gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); - } + if (gWindowImplementation != NULL) + { + gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); + } } void callMouseMoved(float *pos, MASK mask) { - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); - //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); } void callMouseDragged(float *pos, MASK mask) { - LLCoordGL outCoords; + LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); float deltas[2]; @@ -370,78 +370,78 @@ void callMouseDragged(float *pos, MASK mask) void callScrollMoved(float deltaX, float deltaY) { - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); - } + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } } void callMouseExit() { - gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); + gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); } void callWindowFocus() { if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); - } - else - { - LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; - } + { + gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); + } + else + { + LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; + } } void callWindowUnfocus() { - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } } void callWindowHide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); - } +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); + } } void callWindowUnhide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); - } +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); + } } void callWindowDidChangeScreen() { - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); - } + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); + } } void callDeltaUpdate(float *delta, MASK mask) { - gWindowImplementation->updateMouseDeltas(delta); + gWindowImplementation->updateMouseDeltas(delta); } void callOtherMouseDown(float *pos, MASK mask, int button) { - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; if (button == 2) { @@ -455,12 +455,12 @@ void callOtherMouseDown(float *pos, MASK mask, int button) void callOtherMouseUp(float *pos, MASK mask, int button) { - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; if (button == 2) { @@ -474,169 +474,169 @@ void callOtherMouseUp(float *pos, MASK mask, int button) void callModifier(MASK mask) { - gKeyboard->handleModifier(mask); + gKeyboard->handleModifier(mask); } void callHandleDragEntered(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); } void callHandleDragExited(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); } void callHandleDragUpdated(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); } void callHandleDragDropped(std::string url) { - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); } void callQuitHandler() { - if (gWindowImplementation) - { - if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) - { - gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); - } - } + if (gWindowImplementation) + { + if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) + { + gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); + } + } } void getPreeditSelectionRange(int *position, int *length) { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getSelectionRange(position, length); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getSelectionRange(position, length); + } } void getPreeditMarkedRange(int *position, int *length) { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getPreeditRange(position, length); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getPreeditRange(position, length); + } } void setPreeditMarkedRange(int position, int length) { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->markAsPreedit(position, length); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->markAsPreedit(position, length); + } } bool handleUnicodeCharacter(wchar_t c) { bool success = false; - if (gWindowImplementation->getPreeditor()) - { + if (gWindowImplementation->getPreeditor()) + { success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); - } - + } + return success; } void resetPreedit() { - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->resetPreedit(); - } + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->resetPreedit(); + } } // For reasons of convenience, handle IME updates here. // This largely mirrors the old implementation, only sans the carbon parameters. void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments) { - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - preeditor->resetPreedit(); - // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. - if (replacementRange[0] < replacementRange[1]) - { - const LLWString& text = preeditor->getPreeditString(); - const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); - const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); - preeditor->markAsPreedit(location, length); - } - - LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); - - S32 caret_position = fix_str.length(); - - preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); - } + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + preeditor->resetPreedit(); + // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. + if (replacementRange[0] < replacementRange[1]) + { + const LLWString& text = preeditor->getPreeditString(); + const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); + const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); + preeditor->markAsPreedit(location, length); + } + + LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); + + S32 caret_position = fix_str.length(); + + preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); + } } void getPreeditLocation(float *location, unsigned int length) { - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - LLCoordGL coord; - LLCoordScreen screen; - LLRect rect; - - preeditor->getPreeditLocation(length, &coord, &rect, NULL); - - float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; - - convertRectToScreen(gWindowImplementation->getWindow(), c); - - location[0] = c[0]; - location[1] = c[1]; - } + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + LLCoordGL coord; + LLCoordScreen screen; + LLRect rect; + + preeditor->getPreeditLocation(length, &coord, &rect, NULL); + + float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; + + convertRectToScreen(gWindowImplementation->getWindow(), c); + + location[0] = c[0]; + location[1] = c[1]; + } } void LLWindowMacOSX::updateMouseDeltas(float* deltas) { - if (mCursorDecoupled) - { - mCursorLastEventDeltaX = ll_round(deltas[0]); - mCursorLastEventDeltaY = ll_round(-deltas[1]); - - if (mCursorIgnoreNextDelta) - { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - } - } else { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - } + if (mCursorDecoupled) + { + mCursorLastEventDeltaX = ll_round(deltas[0]); + mCursorLastEventDeltaY = ll_round(-deltas[1]); + + if (mCursorIgnoreNextDelta) + { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = FALSE; + } + } else { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + } } void LLWindowMacOSX::getMouseDeltas(float* delta) { - delta[0] = mCursorLastEventDeltaX; - delta[1] = mCursorLastEventDeltaY; + delta[0] = mCursorLastEventDeltaX; + delta[1] = mCursorLastEventDeltaY; } BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync) { - mFullscreen = fullscreen; - - if (mWindow == NULL) - { - mWindow = getMainAppWindow(); - } - - if(mContext == NULL) - { - // Our OpenGL view is already defined within SecondLife.xib. - // Get the view instead. - mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); - mContext = getCGLContextObj(mGLView); - gGLManager.mVRAM = getVramSize(mGLView); + mFullscreen = fullscreen; + + if (mWindow == NULL) + { + mWindow = getMainAppWindow(); + } + + if(mContext == NULL) + { + // Our OpenGL view is already defined within SecondLife.xib. + // Get the view instead. + mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); + mContext = getCGLContextObj(mGLView); + gGLManager.mVRAM = getVramSize(mGLView); if(!mPixelFormat) { @@ -659,30 +659,30 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits GLint numPixelFormats; CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); - + if(mPixelFormat == NULL) { CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); } } - } - - // This sets up our view to recieve text from our non-inline text input window. - setupInputWindow(mWindow, mGLView); - - // Hook up the context to a drawable - - if(mContext != NULL) - { - - - U32 err = CGLSetCurrentContext(mContext); - if (err != kCGLNoError) - { - setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return FALSE; - } - } + } + + // This sets up our view to recieve text from our non-inline text input window. + setupInputWindow(mWindow, mGLView); + + // Hook up the context to a drawable + + if(mContext != NULL) + { + + + U32 err = CGLSetCurrentContext(mContext); + if (err != kCGLNoError) + { + setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); + return FALSE; + } + } mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); if(mRefreshRate == 0) @@ -691,29 +691,29 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits mRefreshRate = DEFAULT_REFRESH_RATE; } - // Disable vertical sync for swap + // Disable vertical sync for swap toggleVSync(enable_vsync); - //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); + //enable multi-threaded OpenGL + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - makeFirstResponder(mWindow, mGLView); - - return TRUE; + } + } + makeFirstResponder(mWindow, mGLView); + + return TRUE; } @@ -721,66 +721,66 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // This makes this method obsolete. BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp) { - return FALSE; + return FALSE; } void LLWindowMacOSX::destroyContext() { - if (!mContext) - { - // We don't have a context - return; - } - // Unhook the GL context from any drawable it may have - if(mContext != NULL) - { - LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; - CGLSetCurrentContext(NULL); - } - - // Clean up remaining GL state before blowing away window - gGLManager.shutdownGL(); - - // Clean up the pixel format - if(mPixelFormat != NULL) - { - CGLDestroyPixelFormat(mPixelFormat); - mPixelFormat = NULL; - } - - // Clean up the GL context - if(mContext != NULL) - { - CGLDestroyContext(mContext); - } - - // Destroy our LLOpenGLView - if(mGLView != NULL) - { - removeGLView(mGLView); - mGLView = NULL; - } - - // Close the window - if(mWindow != NULL) - { + if (!mContext) + { + // We don't have a context + return; + } + // Unhook the GL context from any drawable it may have + if(mContext != NULL) + { + LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; + CGLSetCurrentContext(NULL); + } + + // Clean up remaining GL state before blowing away window + gGLManager.shutdownGL(); + + // Clean up the pixel format + if(mPixelFormat != NULL) + { + CGLDestroyPixelFormat(mPixelFormat); + mPixelFormat = NULL; + } + + // Clean up the GL context + if(mContext != NULL) + { + CGLDestroyContext(mContext); + } + + // Destroy our LLOpenGLView + if(mGLView != NULL) + { + removeGLView(mGLView); + mGLView = NULL; + } + + // Close the window + if(mWindow != NULL) + { NSWindowRef dead_window = mWindow; mWindow = NULL; - closeWindow(dead_window); - } + closeWindow(dead_window); + } } LLWindowMacOSX::~LLWindowMacOSX() { - destroyContext(); + destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + if(mSupportedResolutions != NULL) + { + delete []mSupportedResolutions; + } - gWindowImplementation = NULL; + gWindowImplementation = NULL; } @@ -791,20 +791,20 @@ void LLWindowMacOSX::show() void LLWindowMacOSX::hide() { - setMouseClipping(FALSE); + setMouseClipping(FALSE); } //virtual void LLWindowMacOSX::minimize() { - setMouseClipping(FALSE); - showCursor(); + setMouseClipping(FALSE); + showCursor(); } //virtual void LLWindowMacOSX::restore() { - show(); + show(); } @@ -812,193 +812,193 @@ void LLWindowMacOSX::restore() // Usually called from LLWindowManager::destroyWindow() void LLWindowMacOSX::close() { - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } + // Is window is already closed? + // if (!mWindow) + // { + // return; + // } - // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(FALSE); - showCursor(); + // Make sure cursor is visible and we haven't mangled the clipping state. + setMouseClipping(FALSE); + showCursor(); - destroyContext(); + destroyContext(); } BOOL LLWindowMacOSX::isValid() { - if(mFullscreen) - { - return(TRUE); - } + if(mFullscreen) + { + return(TRUE); + } - return (mWindow != NULL); + return (mWindow != NULL); } BOOL LLWindowMacOSX::getVisible() { - BOOL result = FALSE; + BOOL result = FALSE; - if(mFullscreen) - { - result = TRUE; - }if (mWindow) - { - result = TRUE; - } + if(mFullscreen) + { + result = TRUE; + }if (mWindow) + { + result = TRUE; + } - return(result); + return(result); } BOOL LLWindowMacOSX::getMinimized() { - return mMinimized; + return mMinimized; } BOOL LLWindowMacOSX::getMaximized() { - return mMaximized; + return mMaximized; } BOOL LLWindowMacOSX::maximize() { - if (mWindow && !mMaximized) - { - } + if (mWindow && !mMaximized) + { + } - return mMaximized; + return mMaximized; } BOOL LLWindowMacOSX::getFullscreen() { - return mFullscreen; + return mFullscreen; } void LLWindowMacOSX::gatherInput() { - updateCursor(); + updateCursor(); } BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) { - S32 err = -1; + S32 err = -1; - if(mFullscreen) - { - position->mX = 0; - position->mY = 0; - err = noErr; - } - else if(mWindow) - { - const CGPoint & pos = getContentViewBoundsPosition(mWindow); + if(mFullscreen) + { + position->mX = 0; + position->mY = 0; + err = noErr; + } + else if(mWindow) + { + const CGPoint & pos = getContentViewBoundsPosition(mWindow); - position->mX = pos.x; - position->mY = pos.y; + position->mX = pos.x; + position->mY = pos.y; - err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; - } + err = noErr; + } + else + { + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; + } - return (err == noErr); + return (err == noErr); } BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) { - S32 err = -1; + S32 err = -1; - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - size->mX = sz.width; - size->mY = sz.height; + size->mX = sz.width; + size->mY = sz.height; err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } - return (err == noErr); + return (err == noErr); } BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) { - S32 err = -1; - - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - - size->mX = sz.width; - size->mY = sz.height; + S32 err = -1; + + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + + size->mX = sz.width; + size->mY = sz.height; err = noErr; - - - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); + + + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); } BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) { - if(mWindow) - { - float pos[2] = {float(position.mX), float(position.mY)}; - setWindowPos(mWindow, pos); - } + if(mWindow) + { + float pos[2] = {float(position.mX), float(position.mY)}; + setWindowPos(mWindow, pos); + } - return TRUE; + return TRUE; } BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) { - if(mWindow) - { + if(mWindow) + { LLCoordWindow to; convertCoords(size, &to); - setWindowSize(mWindow, to.mX, to.mY); + setWindowSize(mWindow, to.mX, to.mY); return TRUE; - } + } - return FALSE; + return FALSE; } BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) { - if (mWindow) - { + if (mWindow) + { const int titlePadding = 22; setWindowSize(mWindow, size.mX, size.mY + titlePadding); return TRUE; - } - - return FALSE; + } + + return FALSE; } void LLWindowMacOSX::swapBuffers() { - CGLFlushDrawable(mContext); + CGLFlushDrawable(mContext); } void LLWindowMacOSX::restoreGLContext() @@ -1008,106 +1008,106 @@ void LLWindowMacOSX::restoreGLContext() F32 LLWindowMacOSX::getGamma() { - F32 result = 2.2; // Default to something sane - - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) == noErr) - { - // So many choices... - // Let's just return the green channel gamma for now. - result = greenGamma; - } - - return result; + F32 result = 2.2; // Default to something sane + + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) == noErr) + { + // So many choices... + // Let's just return the green channel gamma for now. + result = greenGamma; + } + + return result; } U32 LLWindowMacOSX::getFSAASamples() { - return mFSAASamples; + return mFSAASamples; } void LLWindowMacOSX::setFSAASamples(const U32 samples) { - mFSAASamples = samples; - mForceRebuild = TRUE; + mFSAASamples = samples; + mForceRebuild = TRUE; } BOOL LLWindowMacOSX::restoreGamma() { - CGDisplayRestoreColorSyncSettings(); - return true; + CGDisplayRestoreColorSyncSettings(); + return true; } BOOL LLWindowMacOSX::setGamma(const F32 gamma) { - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - // MBW -- XXX -- Should we allow this in windowed mode? - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) != noErr) - { - return false; - } - - if(CGSetDisplayTransferByFormula( - mDisplay, - redMin, - redMax, - gamma, - greenMin, - greenMax, - gamma, - blueMin, - blueMax, - gamma) != noErr) - { - return false; - } - - - return true; + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + // MBW -- XXX -- Should we allow this in windowed mode? + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) != noErr) + { + return false; + } + + if(CGSetDisplayTransferByFormula( + mDisplay, + redMin, + redMax, + gamma, + greenMin, + greenMax, + gamma, + blueMin, + blueMax, + gamma) != noErr) + { + return false; + } + + + return true; } BOOL LLWindowMacOSX::isCursorHidden() { - return mCursorHidden; + return mCursorHidden; } @@ -1115,142 +1115,142 @@ BOOL LLWindowMacOSX::isCursorHidden() // Constrains the mouse to the window. void LLWindowMacOSX::setMouseClipping( BOOL b ) { - // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. - mIsMouseClipping = b; + // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. + mIsMouseClipping = b; - if(b) - { - // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; - } - else - { - // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; - } + if(b) + { + // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; + } + else + { + // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; + } - adjustCursorDecouple(); + adjustCursorDecouple(); } BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) { - BOOL result = FALSE; - LLCoordScreen screen_pos; + BOOL result = FALSE; + LLCoordScreen screen_pos; - if (!convertCoords(position, &screen_pos)) - { - return FALSE; - } + if (!convertCoords(position, &screen_pos)) + { + return FALSE; + } - CGPoint newPosition; + CGPoint newPosition; - // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; - newPosition.x = screen_pos.mX; - newPosition.y = screen_pos.mY; + newPosition.x = screen_pos.mX; + newPosition.y = screen_pos.mY; - CGSetLocalEventsSuppressionInterval(0.0); - if(CGWarpMouseCursorPosition(newPosition) == noErr) - { - result = TRUE; - } + CGSetLocalEventsSuppressionInterval(0.0); + if(CGWarpMouseCursorPosition(newPosition) == noErr) + { + result = TRUE; + } - // Under certain circumstances, this will trigger us to decouple the cursor. - adjustCursorDecouple(true); + // Under certain circumstances, this will trigger us to decouple the cursor. + adjustCursorDecouple(true); - // trigger mouse move callback - LLCoordGL gl_pos; - convertCoords(position, &gl_pos); - float scale = getSystemUISize(); - gl_pos.mX *= scale; - gl_pos.mY *= scale; - mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); + // trigger mouse move callback + LLCoordGL gl_pos; + convertCoords(position, &gl_pos); + float scale = getSystemUISize(); + gl_pos.mX *= scale; + gl_pos.mY *= scale; + mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); - return result; + return result; } BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) { - float cursor_point[2]; - LLCoordScreen screen_pos; + float cursor_point[2]; + LLCoordScreen screen_pos; - if(mWindow == NULL) - return FALSE; - - getCursorPos(mWindow, cursor_point); + if(mWindow == NULL) + return FALSE; - if(mCursorDecoupled) - { - // CGMouseDelta x, y; + getCursorPos(mWindow, cursor_point); - // If the cursor's decoupled, we need to read the latest movement delta as well. - // CGGetLastMouseDelta( &x, &y ); - // cursor_point.h += x; - // cursor_point.v += y; + if(mCursorDecoupled) + { + // CGMouseDelta x, y; - // CGGetLastMouseDelta may behave strangely when the cursor's first captured. - // Stash in the event handler instead. - cursor_point[0] += mCursorLastEventDeltaX; - cursor_point[1] += mCursorLastEventDeltaY; - } + // If the cursor's decoupled, we need to read the latest movement delta as well. + // CGGetLastMouseDelta( &x, &y ); + // cursor_point.h += x; + // cursor_point.v += y; - float scale = getSystemUISize(); - position->mX = cursor_point[0] * scale; - position->mY = cursor_point[1] * scale; + // CGGetLastMouseDelta may behave strangely when the cursor's first captured. + // Stash in the event handler instead. + cursor_point[0] += mCursorLastEventDeltaX; + cursor_point[1] += mCursorLastEventDeltaY; + } + + float scale = getSystemUISize(); + position->mX = cursor_point[0] * scale; + position->mY = cursor_point[1] * scale; - return TRUE; + return TRUE; } void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) { - if(mIsMouseClipping && mCursorHidden) - { - if(warpingMouse) - { - // The cursor should be decoupled. Make sure it is. - if(!mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(false); - mCursorDecoupled = true; - mCursorIgnoreNextDelta = TRUE; - } - } - } - else - { - // The cursor should not be decoupled. Make sure it isn't. - if(mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(true); - mCursorDecoupled = false; - } - } + if(mIsMouseClipping && mCursorHidden) + { + if(warpingMouse) + { + // The cursor should be decoupled. Make sure it is. + if(!mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(false); + mCursorDecoupled = true; + mCursorIgnoreNextDelta = TRUE; + } + } + } + else + { + // The cursor should not be decoupled. Make sure it isn't. + if(mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(true); + mCursorDecoupled = false; + } + } } F32 LLWindowMacOSX::getNativeAspectRatio() { - if (mFullscreen) - { - return (F32)mFullscreenWidth / (F32)mFullscreenHeight; - } - else - { - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. + if (mFullscreen) + { + return (F32)mFullscreenWidth / (F32)mFullscreenHeight; + } + else + { + // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution + // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } - return mOriginalAspectRatio; - } + return mOriginalAspectRatio; + } } F32 LLWindowMacOSX::getPixelAspectRatio() { - //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode - return 1.f; + //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode + return 1.f; } U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { @@ -1281,165 +1281,165 @@ void LLWindowMacOSX::afterDialog() void LLWindowMacOSX::flashIcon(F32 seconds) { - // For consistency with OS X conventions, the number of seconds given is ignored and - // left up to the OS (which will actually bounce it for one second). - requestUserAttention(); + // For consistency with OS X conventions, the number of seconds given is ignored and + // left up to the OS (which will actually bounce it for one second). + requestUserAttention(); } BOOL LLWindowMacOSX::isClipboardTextAvailable() { - return pasteBoardAvailable(); + return pasteBoardAvailable(); } BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) { unsigned short* pboard_data = copyFromPBoard(); // must free returned data - llutf16string str(pboard_data); + llutf16string str(pboard_data); free(pboard_data); - dst = utf16str_to_wstring(str); - if (dst != L"") - { - return true; - } else { - return false; - } + dst = utf16str_to_wstring(str); + if (dst != L"") + { + return true; + } else { + return false; + } } BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) { - BOOL result = false; - llutf16string utf16str = wstring_to_utf16str(s); - - result = copyToPBoard(utf16str.data(), utf16str.length()); + BOOL result = false; + llutf16string utf16str = wstring_to_utf16str(s); + + result = copyToPBoard(utf16str.data(), utf16str.length()); - return result; + return result; } // protected BOOL LLWindowMacOSX::resetDisplayResolution() { - // This is only called from elsewhere in this class, and it's not used by the Mac implementation. - return true; + // This is only called from elsewhere in this class, and it's not used by the Mac implementation. + return true; } LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) { - if (!mSupportedResolutions) - { - CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); - - if(modes != NULL) - { - CFIndex index, cnt; - - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - mNumSupportedResolutions = 0; - - // Examine each mode - cnt = CFArrayGetCount( modes ); - - for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) - { - // Pull the mode dictionary out of the CFArray - CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); - long width = getDictLong(mode, kCGDisplayWidth); - long height = getDictLong(mode, kCGDisplayHeight); - long bits = getDictLong(mode, kCGDisplayBitsPerPixel); - - if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) - { - BOOL resolution_exists = FALSE; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == width && - mSupportedResolutions[i].mHeight == height) - { - resolution_exists = TRUE; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = width; - mSupportedResolutions[mNumSupportedResolutions].mHeight = height; - mNumSupportedResolutions++; - } - } - } + if (!mSupportedResolutions) + { + CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); + + if(modes != NULL) + { + CFIndex index, cnt; + + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + mNumSupportedResolutions = 0; + + // Examine each mode + cnt = CFArrayGetCount( modes ); + + for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) + { + // Pull the mode dictionary out of the CFArray + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); + long width = getDictLong(mode, kCGDisplayWidth); + long height = getDictLong(mode, kCGDisplayHeight); + long bits = getDictLong(mode, kCGDisplayBitsPerPixel); + + if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) + { + BOOL resolution_exists = FALSE; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == width && + mSupportedResolutions[i].mHeight == height) + { + resolution_exists = TRUE; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = width; + mSupportedResolutions[mNumSupportedResolutions].mHeight = height; + mNumSupportedResolutions++; + } + } + } CFRelease(modes); - } - } + } + } - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; } BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) { - to->mX = from.mX; - to->mY = from.mY; - return TRUE; + to->mX = from.mX; + to->mY = from.mY; + return TRUE; } BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) { - to->mX = from.mX; - to->mY = from.mY; - return TRUE; + to->mX = from.mX; + to->mY = from.mY; + return TRUE; } BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) { - if(mWindow) - { - float mouse_point[2]; + if(mWindow) + { + float mouse_point[2]; + + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; - - convertScreenToWindow(mWindow, mouse_point); + convertScreenToWindow(mWindow, mouse_point); - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; - return TRUE; - } - return FALSE; + return TRUE; + } + return FALSE; } BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) { - if(mWindow) - { - float mouse_point[2]; + if(mWindow) + { + float mouse_point[2]; + + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; - - convertWindowToScreen(mWindow, mouse_point); + convertWindowToScreen(mWindow, mouse_point); - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; - return TRUE; - } - return FALSE; + return TRUE; + } + return FALSE; } BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } @@ -1447,66 +1447,66 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) { - destroyContext(); + destroyContext(); - OSMessageBox(text, caption, type); + OSMessageBox(text, caption, type); } - // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature - // it is handled at a very low-level + // 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) - { - case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; - case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; - case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; - case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; - case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; - case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; - case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; - case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; - case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; - case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; - case UI_CURSOR_NO: return "UI_CURSOR_NO"; - case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; - case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; - case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; - case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; - case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; - case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; - case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; - case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; - case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; - case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; - case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; - case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; - case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; - case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; - case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; - case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; - case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; - case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; - case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; - case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; - case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; - case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; - case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; - case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; - case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; - case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; - case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; - case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; - } - - LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; - - return "UI_CURSOR_ARROW"; + switch (id) + { + case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; + case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; + case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; + case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; + case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; + case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; + case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; + case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; + case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; + case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; + case UI_CURSOR_NO: return "UI_CURSOR_NO"; + case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; + case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; + case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; + case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; + case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; + case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; + case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; + case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; + case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; + case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; + case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; + case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; + case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; + case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; + case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; + case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; + case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; + case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; + case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; + case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; + case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; + case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; + case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; + case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; + case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; + case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; + case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; + case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; + case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; + } + + LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; + + return "UI_CURSOR_ARROW"; } static CursorRef gCursors[UI_CURSOR_COUNT]; @@ -1514,233 +1514,233 @@ static CursorRef gCursors[UI_CURSOR_COUNT]; static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) { - // cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif - std::string fullpath = gDirUtilp->add( - gDirUtilp->getAppRODataDir(), - "cursors_mac", - cursorIDToName(cursorid) + std::string(".tif")); + // cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif + std::string fullpath = gDirUtilp->add( + gDirUtilp->getAppRODataDir(), + "cursors_mac", + cursorIDToName(cursorid) + std::string(".tif")); - gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); + gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); } void LLWindowMacOSX::updateCursor() { - S32 result = 0; - - if (mDragOverrideCursor != -1) - { - // A drag is in progress...remember the requested cursor and we'll - // restore it when it is done - mCurrentCursor = mNextCursor; - return; - } - - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - + S32 result = 0; + + if (mDragOverrideCursor != -1) + { + // A drag is in progress...remember the requested cursor and we'll + // restore it when it is done + mCurrentCursor = mNextCursor; + return; + } + + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + if(mCurrentCursor == mNextCursor) { if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) { - hideNSCursor(); + hideNSCursor(); adjustCursorDecouple(); } return; } - // RN: replace multi-drag cursors with single versions - if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) - { - mNextCursor = UI_CURSOR_ARROWDRAG; - } - else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) - { - mNextCursor = UI_CURSOR_ARROWCOPY; - } - - switch(mNextCursor) - { - default: - case UI_CURSOR_ARROW: - setArrowCursor(); - if(mCursorHidden) - { - // Since InitCursor resets the hide level, correct for it here. - hideNSCursor(); - } - break; - - // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. - // Find out what they look like and replicate them. - - // These are essentially correct - case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; - case UI_CURSOR_IBEAM: setIBeamCursor(); break; - case UI_CURSOR_CROSS: setCrossCursor(); break; - case UI_CURSOR_HAND: setPointingHandCursor(); break; - // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; - case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; - - // Double-check these - case UI_CURSOR_NO: - case UI_CURSOR_SIZEWE: - case UI_CURSOR_SIZENS: - case UI_CURSOR_SIZENWSE: - case UI_CURSOR_SIZENESW: - case UI_CURSOR_WORKING: - case UI_CURSOR_TOOLGRAB: - case UI_CURSOR_TOOLLAND: - case UI_CURSOR_TOOLFOCUS: - case UI_CURSOR_TOOLCREATE: - case UI_CURSOR_ARROWDRAG: - case UI_CURSOR_NOLOCKED: - case UI_CURSOR_ARROWLOCKED: - case UI_CURSOR_GRABLOCKED: - case UI_CURSOR_PIPETTE: - case UI_CURSOR_TOOLTRANSLATE: - case UI_CURSOR_TOOLROTATE: - case UI_CURSOR_TOOLSCALE: - case UI_CURSOR_TOOLCAMERA: - case UI_CURSOR_TOOLPAN: - case UI_CURSOR_TOOLZOOMIN: - case UI_CURSOR_TOOLPICKOBJECT3: - case UI_CURSOR_TOOLPLAY: - case UI_CURSOR_TOOLPAUSE: - case UI_CURSOR_TOOLMEDIAOPEN: - case UI_CURSOR_TOOLSIT: - case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLOPEN: - case UI_CURSOR_TOOLPATHFINDING: - case UI_CURSOR_TOOLPATHFINDING_PATH_START: - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: - case UI_CURSOR_TOOLPATHFINDING_PATH_END: - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: - case UI_CURSOR_TOOLNO: - result = setImageCursor(gCursors[mNextCursor]); - break; - - } - - if(result != noErr) - { - setArrowCursor(); - } - - mCurrentCursor = mNextCursor; + // RN: replace multi-drag cursors with single versions + if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) + { + mNextCursor = UI_CURSOR_ARROWDRAG; + } + else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) + { + mNextCursor = UI_CURSOR_ARROWCOPY; + } + + switch(mNextCursor) + { + default: + case UI_CURSOR_ARROW: + setArrowCursor(); + if(mCursorHidden) + { + // Since InitCursor resets the hide level, correct for it here. + hideNSCursor(); + } + break; + + // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. + // Find out what they look like and replicate them. + + // These are essentially correct + case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; + case UI_CURSOR_IBEAM: setIBeamCursor(); break; + case UI_CURSOR_CROSS: setCrossCursor(); break; + case UI_CURSOR_HAND: setPointingHandCursor(); break; + // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; + case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; + + // Double-check these + case UI_CURSOR_NO: + case UI_CURSOR_SIZEWE: + case UI_CURSOR_SIZENS: + case UI_CURSOR_SIZENWSE: + case UI_CURSOR_SIZENESW: + case UI_CURSOR_WORKING: + case UI_CURSOR_TOOLGRAB: + case UI_CURSOR_TOOLLAND: + case UI_CURSOR_TOOLFOCUS: + case UI_CURSOR_TOOLCREATE: + case UI_CURSOR_ARROWDRAG: + case UI_CURSOR_NOLOCKED: + case UI_CURSOR_ARROWLOCKED: + case UI_CURSOR_GRABLOCKED: + case UI_CURSOR_PIPETTE: + case UI_CURSOR_TOOLTRANSLATE: + case UI_CURSOR_TOOLROTATE: + case UI_CURSOR_TOOLSCALE: + case UI_CURSOR_TOOLCAMERA: + case UI_CURSOR_TOOLPAN: + case UI_CURSOR_TOOLZOOMIN: + case UI_CURSOR_TOOLPICKOBJECT3: + case UI_CURSOR_TOOLPLAY: + case UI_CURSOR_TOOLPAUSE: + case UI_CURSOR_TOOLMEDIAOPEN: + case UI_CURSOR_TOOLSIT: + case UI_CURSOR_TOOLBUY: + case UI_CURSOR_TOOLOPEN: + case UI_CURSOR_TOOLPATHFINDING: + case UI_CURSOR_TOOLPATHFINDING_PATH_START: + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: + case UI_CURSOR_TOOLPATHFINDING_PATH_END: + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: + case UI_CURSOR_TOOLNO: + result = setImageCursor(gCursors[mNextCursor]); + break; + + } + + if(result != noErr) + { + setArrowCursor(); + } + + mCurrentCursor = mNextCursor; } ECursorType LLWindowMacOSX::getCursor() const { - return mCurrentCursor; + return mCurrentCursor; } void LLWindowMacOSX::initCursors() { - initPixmapCursor(UI_CURSOR_NO, 8, 8); - initPixmapCursor(UI_CURSOR_WORKING, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); - initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); - initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); - initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); - initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); - initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); - initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); - initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); - initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); - initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); + initPixmapCursor(UI_CURSOR_NO, 8, 8); + initPixmapCursor(UI_CURSOR_WORKING, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); + initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); + initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); + initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); + initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); + initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); + initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); + initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); + initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); + initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); - - initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); - initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); + initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); + + initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); + initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10); } void LLWindowMacOSX::captureMouse() { - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. } void LLWindowMacOSX::releaseMouse() { - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. } void LLWindowMacOSX::hideCursor() { - if(!mCursorHidden) - { - // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; - hideNSCursor(); - } - else - { - // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; - } + if(!mCursorHidden) + { + // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; + mCursorHidden = TRUE; + mHideCursorPermanent = TRUE; + hideNSCursor(); + } + else + { + // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; + } - adjustCursorDecouple(); + adjustCursorDecouple(); } void LLWindowMacOSX::showCursor() { - if(mCursorHidden || !isCGCursorVisible()) - { - // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; - showNSCursor(); - } - else - { - // LL_INFOS() << "showCursor: already visible" << LL_ENDL; - } + if(mCursorHidden || !isCGCursorVisible()) + { + // LL_INFOS() << "showCursor: showing" << LL_ENDL; + mCursorHidden = FALSE; + mHideCursorPermanent = FALSE; + showNSCursor(); + } + else + { + // LL_INFOS() << "showCursor: already visible" << LL_ENDL; + } - adjustCursorDecouple(); + adjustCursorDecouple(); } void LLWindowMacOSX::showCursorFromMouseMove() { - if (!mHideCursorPermanent) - { - showCursor(); - } + if (!mHideCursorPermanent) + { + showCursor(); + } } void LLWindowMacOSX::hideCursorUntilMouseMove() { - if (!mHideCursorPermanent) - { - hideCursor(); - mHideCursorPermanent = FALSE; - } + if (!mHideCursorPermanent) + { + hideCursor(); + mHideCursorPermanent = FALSE; + } } @@ -1750,7 +1750,7 @@ void LLWindowMacOSX::hideCursorUntilMouseMove() // LLSplashScreenMacOSX::LLSplashScreenMacOSX() { - mWindow = NULL; + mWindow = NULL; } LLSplashScreenMacOSX::~LLSplashScreenMacOSX() @@ -1759,201 +1759,201 @@ LLSplashScreenMacOSX::~LLSplashScreenMacOSX() void LLSplashScreenMacOSX::showImpl() { - // This code _could_ be used to display a spash screen... + // This code _could_ be used to display a spash screen... } void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) { - if(mWindow != NULL) - { - CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); - } + if(mWindow != NULL) + { + CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); + } } void LLSplashScreenMacOSX::hideImpl() { - if(mWindow != NULL) - { - mWindow = NULL; - } + if(mWindow != NULL) + { + mWindow = NULL; + } } S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) { - return showAlert(text, caption, type); + return showAlert(text, caption, type); } // Open a URL with the user's default web browser. // Must begin with protocol identifier. void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) { - // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. - - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - S32 result = 0; - CFURLRef urlRef = NULL; - - LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; - - CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); - if (stringRef) - { - // This will succeed if the string is a full URL, including the http:// - // Note that URLs specified this way need to be properly percent-escaped. - urlRef = CFURLCreateWithString(NULL, stringRef, NULL); - - // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs - - CFRelease(stringRef); - } - - if (urlRef) - { - result = LSOpenCFURLRef(urlRef, NULL); - - if (result != noErr) - { - LL_INFOS() << "Error " << result << " on open." << LL_ENDL; - } - - CFRelease(urlRef); - } - else - { - LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; - } + // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. + + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + S32 result = 0; + CFURLRef urlRef = NULL; + + LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; + + CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); + if (stringRef) + { + // This will succeed if the string is a full URL, including the http:// + // Note that URLs specified this way need to be properly percent-escaped. + urlRef = CFURLCreateWithString(NULL, stringRef, NULL); + + // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs + + CFRelease(stringRef); + } + + if (urlRef) + { + result = LSOpenCFURLRef(urlRef, NULL); + + if (result != noErr) + { + LL_INFOS() << "Error " << result << " on open." << LL_ENDL; + } + + CFRelease(urlRef); + } + else + { + LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; + } } LLSD LLWindowMacOSX::getNativeKeyData() { - LLSD result = LLSD::emptyMap(); + LLSD result = LLSD::emptyMap(); - if(mRawKeyEvent) - { + if(mRawKeyEvent) + { result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); - } + } - LL_DEBUGS() << "native key data is: " << result << LL_ENDL; + LL_DEBUGS() << "native key data is: " << result << LL_ENDL; - return result; + return result; } BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - BOOL retval = FALSE; - OSErr error = noErr; - NColorPickerInfo info; - - memset(&info, 0, sizeof(info)); - info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); - info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); - info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); - info.placeWhere = kCenterOnMainScreen; - - error = NPickColor(&info); - - if (error == noErr) - { - retval = info.newColorChosen; - if (info.newColorChosen) - { - *r = ((float) info.theColor.color.rgb.red) / 65535.0; - *g = ((float) info.theColor.color.rgb.green) / 65535.0; - *b = ((float) info.theColor.color.rgb.blue) / 65535.0; - } - } - - return (retval); + BOOL retval = FALSE; + OSErr error = noErr; + NColorPickerInfo info; + + memset(&info, 0, sizeof(info)); + info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); + info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); + info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); + info.placeWhere = kCenterOnMainScreen; + + error = NPickColor(&info); + + if (error == noErr) + { + retval = info.newColorChosen; + if (info.newColorChosen) + { + *r = ((float) info.theColor.color.rgb.red) / 65535.0; + *g = ((float) info.theColor.color.rgb.green) / 65535.0; + *b = ((float) info.theColor.color.rgb.blue) / 65535.0; + } + } + + return (retval); } void *LLWindowMacOSX::getPlatformWindow() { - // NOTE: this will be NULL in fullscreen mode. Plan accordingly. - return (void*)mWindow; + // NOTE: this will be NULL in fullscreen mode. Plan accordingly. + return (void*)mWindow; } // get a double value from a dictionary /* static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) { - double double_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it - return -1; // fail - return double_value; // otherwise return the long value + double double_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it + return -1; // fail + return double_value; // otherwise return the long value }*/ // get a long value from a dictionary static long getDictLong (CFDictionaryRef refDict, CFStringRef key) { - long int_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it - return -1; // fail - return int_value; // otherwise return the long value + long int_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it + return -1; // fail + return int_value; // otherwise return the long value } void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { - if (preeditor != mPreeditor && !b) - { - // This condition may occur by a call to - // setEnabled(BOOL) against LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - // We need to interrupt before updating mPreeditor, - // so that the fix string from input method goes to - // the old preeditor. - if (mLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - if (b == mLanguageTextInputAllowed) - { - return; - } - mLanguageTextInputAllowed = b; + if (preeditor != mPreeditor && !b) + { + // This condition may occur by a call to + // setEnabled(BOOL) against LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + // We need to interrupt before updating mPreeditor, + // so that the fix string from input method goes to + // the old preeditor. + if (mLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + if (b == mLanguageTextInputAllowed) + { + return; + } + mLanguageTextInputAllowed = b; allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit } -class sharedContext +class sharedContext { public: CGLContextObj mContext; @@ -1963,7 +1963,7 @@ void* LLWindowMacOSX::createSharedContext() { sharedContext* sc = new sharedContext(); CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); - + if (sUseMultGL) { CGLEnable(mContext, kCGLCEMPEngine); @@ -1977,23 +1977,23 @@ void LLWindowMacOSX::makeContextCurrent(void* context) CGLSetCurrentContext(((sharedContext*)context)->mContext); //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); - - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - + } + } + } void LLWindowMacOSX::destroySharedContext(void* context) @@ -2016,64 +2016,64 @@ void LLWindowMacOSX::toggleVSync(bool enable_vsync) { frames_per_swap = 1; } - + CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); } void LLWindowMacOSX::interruptLanguageTextInput() { - commitCurrentPreedit(mGLView); + commitCurrentPreedit(mGLView); } std::vector LLWindowMacOSX::getDisplaysResolutionList() { - std::vector resolution_list; - - CGDirectDisplayID display_ids[10]; - uint32_t found_displays = 0; - CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); - - if (kCGErrorSuccess != err) - { - LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; - return std::vector(); - } - - for (uint32_t i = 0; i < found_displays; i++) - { - S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); - S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); - - resolution_list.push_back(res); - } - - return resolution_list; + std::vector resolution_list; + + CGDirectDisplayID display_ids[10]; + uint32_t found_displays = 0; + CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); + + if (kCGErrorSuccess != err) + { + LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; + return std::vector(); + } + + for (uint32_t i = 0; i < found_displays; i++) + { + S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); + S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + resolution_list.push_back(res); + } + + return resolution_list; } //static std::vector LLWindowMacOSX::getDynamicFallbackFontList() { - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector(); + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector(); } // static MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) { - MASK mask = 0; - if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } - if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } - if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } - return mask; + MASK mask = 0; + if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } + if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } + if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } + return mask; } F32 LLWindowMacOSX::getSystemUISize() { - return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); + return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); } void LLWindowMacOSX::openFolder(const std::string &path) @@ -2084,103 +2084,103 @@ void LLWindowMacOSX::openFolder(const std::string &path) #if LL_OS_DRAGDROP_ENABLED /* S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, - void * handlerRefCon, DragRef drag) + void * handlerRefCon, DragRef drag) { - S16 result = 0; - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + S16 result = 0; + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; + LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; - switch(message) - { - case kDragTrackingInWindow: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); - break; + switch(message) + { + case kDragTrackingInWindow: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); + break; - case kDragTrackingEnterHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); - break; + case kDragTrackingEnterHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); + break; - case kDragTrackingLeaveHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); - break; + case kDragTrackingLeaveHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); + break; - default: - break; - } + default: + break; + } - return result; + return result; } OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, - DragRef drag) + DragRef drag) { - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); } */ void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) { - MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); - - float mouse_point[2]; - // This will return the mouse point in window coords - getCursorPos(mWindow, mouse_point); - LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); - LLCoordGL gl_pos; - convertCoords(window_coords, &gl_pos); - - if(!url.empty()) - { - LLWindowCallbacks::DragNDropResult res = - mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); - - switch (res) { - case LLWindowCallbacks::DND_NONE: // No drop allowed - if (action == LLWindowCallbacks::DNDA_TRACK) - { - mDragOverrideCursor = 0; - } - else { - mDragOverrideCursor = -1; - } - break; - case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation - mDragOverrideCursor = UI_CURSOR_NO; - break; - case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation - mDragOverrideCursor = UI_CURSOR_ARROWCOPY; - break; - default: - mDragOverrideCursor = -1; - break; - } - // This overrides the cursor being set by setCursor. - // This is a bit of a hack workaround because lots of areas - // within the viewer just blindly set the cursor. - if (mDragOverrideCursor == -1) - { - // Restore the cursor - ECursorType temp_cursor = mCurrentCursor; - // get around the "setting the same cursor" code in setCursor() - mCurrentCursor = UI_CURSOR_COUNT; - setCursor(temp_cursor); - } - else { - // Override the cursor - switch (mDragOverrideCursor) { - case 0: - setArrowCursor(); - break; - case UI_CURSOR_NO: - setNotAllowedCursor(); - case UI_CURSOR_ARROWCOPY: - setCopyCursor(); - default: - break; - }; - } - } + MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); + + float mouse_point[2]; + // This will return the mouse point in window coords + getCursorPos(mWindow, mouse_point); + LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); + LLCoordGL gl_pos; + convertCoords(window_coords, &gl_pos); + + if(!url.empty()) + { + LLWindowCallbacks::DragNDropResult res = + mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); + + switch (res) { + case LLWindowCallbacks::DND_NONE: // No drop allowed + if (action == LLWindowCallbacks::DNDA_TRACK) + { + mDragOverrideCursor = 0; + } + else { + mDragOverrideCursor = -1; + } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = UI_CURSOR_NO; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = UI_CURSOR_ARROWCOPY; + break; + default: + mDragOverrideCursor = -1; + break; + } + // This overrides the cursor being set by setCursor. + // This is a bit of a hack workaround because lots of areas + // within the viewer just blindly set the cursor. + if (mDragOverrideCursor == -1) + { + // Restore the cursor + ECursorType temp_cursor = mCurrentCursor; + // get around the "setting the same cursor" code in setCursor() + mCurrentCursor = UI_CURSOR_COUNT; + setCursor(temp_cursor); + } + else { + // Override the cursor + switch (mDragOverrideCursor) { + case 0: + setArrowCursor(); + break; + case UI_CURSOR_NO: + setNotAllowedCursor(); + case UI_CURSOR_ARROWCOPY: + setCopyCursor(); + default: + break; + }; + } + } } #endif // LL_OS_DRAGDROP_ENABLED diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 5f728fb72e..eb1da73c4e 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -1,25 +1,25 @@ -/** +/** * @file llwindowmacosx.h * @brief Mac implementation of LLWindow class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,96 +44,96 @@ class LLWindowMacOSX : public LLWindow { public: - void show() override; - void hide() override; - void close() override; - BOOL getVisible() override; - BOOL getMinimized() override; - BOOL getMaximized() override; - BOOL maximize() override; - void minimize() override; - void restore() override; - BOOL getFullscreen(); - BOOL getPosition(LLCoordScreen *position) override; - BOOL getSize(LLCoordScreen *size) override; - BOOL getSize(LLCoordWindow *size) override; - BOOL setPosition(LLCoordScreen position) override; - BOOL setSizeImpl(LLCoordScreen size) override; - BOOL setSizeImpl(LLCoordWindow size) override; - BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override; - BOOL setCursorPosition(LLCoordWindow position) override; - BOOL getCursorPosition(LLCoordWindow *position) override; - void showCursor() override; - void hideCursor() override; - void showCursorFromMouseMove() override; - void hideCursorUntilMouseMove() override; - BOOL isCursorHidden() override; - void updateCursor() override; - ECursorType getCursor() const override; - void captureMouse() override; - void releaseMouse() override; - void setMouseClipping( BOOL b ) override; - BOOL isClipboardTextAvailable() override; - BOOL pasteTextFromClipboard(LLWString &dst) override; - BOOL copyTextToClipboard(const LLWString & src) override; - void flashIcon(F32 seconds) override; - F32 getGamma() override; - BOOL setGamma(const F32 gamma) override; // Set the gamma - U32 getFSAASamples() override; - void setFSAASamples(const U32 fsaa_samples) override; - BOOL restoreGamma() override; // Restore original gamma table (before updating gamma) - ESwapMethod getSwapMethod() override { return mSwapMethod; } - void gatherInput() override; - void delayInputProcessing() override {}; - void swapBuffers() override; - - // handy coordinate space conversion routines - BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; - BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; - BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; - BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; - BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; - BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; - - LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; - F32 getNativeAspectRatio() override; - F32 getPixelAspectRatio() override; - void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - - // query VRAM usage + void show() override; + void hide() override; + void close() override; + BOOL getVisible() override; + BOOL getMinimized() override; + BOOL getMaximized() override; + BOOL maximize() override; + void minimize() override; + void restore() override; + BOOL getFullscreen(); + BOOL getPosition(LLCoordScreen *position) override; + BOOL getSize(LLCoordScreen *size) override; + BOOL getSize(LLCoordWindow *size) override; + BOOL setPosition(LLCoordScreen position) override; + BOOL setSizeImpl(LLCoordScreen size) override; + BOOL setSizeImpl(LLCoordWindow size) override; + BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override; + BOOL setCursorPosition(LLCoordWindow position) override; + BOOL getCursorPosition(LLCoordWindow *position) override; + void showCursor() override; + void hideCursor() override; + void showCursorFromMouseMove() override; + void hideCursorUntilMouseMove() override; + BOOL isCursorHidden() override; + void updateCursor() override; + ECursorType getCursor() const override; + void captureMouse() override; + void releaseMouse() override; + void setMouseClipping( BOOL b ) override; + BOOL isClipboardTextAvailable() override; + BOOL pasteTextFromClipboard(LLWString &dst) override; + BOOL copyTextToClipboard(const LLWString & src) override; + void flashIcon(F32 seconds) override; + F32 getGamma() override; + BOOL setGamma(const F32 gamma) override; // Set the gamma + U32 getFSAASamples() override; + void setFSAASamples(const U32 fsaa_samples) override; + BOOL restoreGamma() override; // Restore original gamma table (before updating gamma) + ESwapMethod getSwapMethod() override { return mSwapMethod; } + void gatherInput() override; + void delayInputProcessing() override {}; + void swapBuffers() override; + + // handy coordinate space conversion routines + BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; + BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; + BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; + BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; + + LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; + F32 getNativeAspectRatio() override; + F32 getPixelAspectRatio() override; + void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } + + // query VRAM usage /*virtual*/ U32 getAvailableVRAMMegabytes() override; - void beforeDialog() override; - void afterDialog() override; + void beforeDialog() override; + void afterDialog() override; + + BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; - BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; + void *getPlatformWindow() override; + void bringToFront() override {}; - void *getPlatformWindow() override; - void bringToFront() override {}; - - void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override; - void interruptLanguageTextInput() override; - void spawnWebBrowser(const std::string& escaped_url, bool async) override; - F32 getSystemUISize() override; + void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override; + void interruptLanguageTextInput() override; + void spawnWebBrowser(const std::string& escaped_url, bool async) override; + F32 getSystemUISize() override; void openFolder(const std::string &path) override; - static std::vector getDisplaysResolutionList(); - - static std::vector getDynamicFallbackFontList(); - - // Provide native key event data - LLSD getNativeKeyData() override; - - void* getWindow() { return mWindow; } - LLWindowCallbacks* getCallbacks() { return mCallbacks; } - LLPreeditor* getPreeditor() { return mPreeditor; } - - void updateMouseDeltas(float* deltas); - void getMouseDeltas(float* delta); - - void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); - + static std::vector getDisplaysResolutionList(); + + static std::vector getDynamicFallbackFontList(); + + // Provide native key event data + LLSD getNativeKeyData() override; + + void* getWindow() { return mWindow; } + LLWindowCallbacks* getCallbacks() { return mCallbacks; } + LLPreeditor* getPreeditor() { return mPreeditor; } + + void updateMouseDeltas(float* deltas); + void getMouseDeltas(float* delta); + + void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); + bool allowsLanguageInput() { return mLanguageTextInputAllowed; } //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread @@ -148,29 +148,29 @@ public: void toggleVSync(bool enable_vsync) override; protected: - LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, - U32 fsaa_samples); - ~LLWindowMacOSX(); + LLWindowMacOSX(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, + BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, + U32 fsaa_samples); + ~LLWindowMacOSX(); + + void initCursors(); + BOOL isValid() override; + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - void initCursors(); - BOOL isValid() override; - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + // Changes display resolution. Returns true if successful + BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + // Go back to last fullscreen display resolution. + BOOL setFullscreenResolution(); - // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); + // Restore the display resolution to its value before we ran the app. + BOOL resetDisplayResolution(); - // Restore the display resolution to its value before we ran the app. - BOOL resetDisplayResolution(); + BOOL shouldPostQuit() { return mPostQuit; } - BOOL shouldPostQuit() { return mPostQuit; } - //Satisfy MAINT-3135 and MAINT-3288 with a flag. /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } @@ -178,81 +178,81 @@ private: void restoreGLContext(); protected: - // - // Platform specific methods - // - - // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync); - void destroyContext(); - void setupFailure(const std::string& text, const std::string& caption, U32 type); - void adjustCursorDecouple(bool warpingMouse = false); - static MASK modifiersToMask(S16 modifiers); - + // + // Platform specific methods + // + + // create or re-create the GL context/window. Called from the constructor and switchContext(). + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync); + void destroyContext(); + void setupFailure(const std::string& text, const std::string& caption, U32 type); + void adjustCursorDecouple(bool warpingMouse = false); + static MASK modifiersToMask(S16 modifiers); + #if LL_OS_DRAGDROP_ENABLED - - //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - - + + //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + + #endif // LL_OS_DRAGDROP_ENABLED - - // - // Platform specific variables - // - - // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. - NSWindowRef mWindow; - GLViewRef mGLView; - CGLContextObj mContext; - CGLPixelFormatObj mPixelFormat; - CGDirectDisplayID mDisplay; - - LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - std::string mWindowTitle; - double mOriginalAspectRatio; - BOOL mSimulatedRightClick; - U32 mLastModifiers; - BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. - // Used to allow event processing when putting up dialogs in fullscreen mode. - BOOL mCursorDecoupled; - S32 mCursorLastEventDeltaX; - S32 mCursorLastEventDeltaY; - BOOL mCursorIgnoreNextDelta; - BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. - LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - BOOL mMaximized; - BOOL mMinimized; - U32 mFSAASamples; - BOOL mForceRebuild; - - S32 mDragOverrideCursor; - - // Input method management through Text Service Manager. - BOOL mLanguageTextInputAllowed; - LLPreeditor* mPreeditor; - + + // + // Platform specific variables + // + + // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. + NSWindowRef mWindow; + GLViewRef mGLView; + CGLContextObj mContext; + CGLPixelFormatObj mPixelFormat; + CGDirectDisplayID mDisplay; + + LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + std::string mWindowTitle; + double mOriginalAspectRatio; + BOOL mSimulatedRightClick; + U32 mLastModifiers; + BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. + // Used to allow event processing when putting up dialogs in fullscreen mode. + BOOL mCursorDecoupled; + S32 mCursorLastEventDeltaX; + S32 mCursorLastEventDeltaY; + BOOL mCursorIgnoreNextDelta; + BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + LLCoordScreen mNeedsResizeSize; + F32 mOverrideAspectRatio; + BOOL mMaximized; + BOOL mMinimized; + U32 mFSAASamples; + BOOL mForceRebuild; + + S32 mDragOverrideCursor; + + // Input method management through Text Service Manager. + BOOL mLanguageTextInputAllowed; + LLPreeditor* mPreeditor; + public: - static BOOL sUseMultGL; + static BOOL sUseMultGL; + + friend class LLWindowManager; - friend class LLWindowManager; - }; class LLSplashScreenMacOSX : public LLSplashScreen { public: - LLSplashScreenMacOSX(); - virtual ~LLSplashScreenMacOSX(); + LLSplashScreenMacOSX(); + virtual ~LLSplashScreenMacOSX(); - void showImpl(); - void updateImpl(const std::string& mesg); - void hideImpl(); + void showImpl(); + void updateImpl(const std::string& mesg); + void hideImpl(); private: - WindowRef mWindow; + WindowRef mWindow; }; S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index dd776e5a0f..2e405da44a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llwindowwin32.cpp * @brief Platform-dependent implementation of llwindow * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,7 +53,7 @@ #include #include #include -#include // for _spawn +#include // for _spawn #include #include #include @@ -75,10 +75,10 @@ #pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems #pragma comment(lib, "dinput8") -const S32 MAX_MESSAGE_PER_UPDATE = 20; -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; -const F32 ICON_FLASH_TIME = 0.5f; +const S32 MAX_MESSAGE_PER_UPDATE = 20; +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; +const F32 ICON_FLASH_TIME = 0.5f; #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 @@ -114,16 +114,16 @@ LLW32MsgCallback gAsyncMsgCallback = NULL; #ifndef DPI_ENUMS_DECLARED typedef enum PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; typedef enum MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; #endif @@ -131,14 +131,14 @@ typedef enum MONITOR_DPI_TYPE { typedef HRESULT(STDAPICALLTYPE *SetProcessDpiAwarenessType)(_In_ PROCESS_DPI_AWARENESS value); typedef HRESULT(STDAPICALLTYPE *GetProcessDpiAwarenessType)( - _In_ HANDLE hprocess, - _Out_ PROCESS_DPI_AWARENESS *value); + _In_ HANDLE hprocess, + _Out_ PROCESS_DPI_AWARENESS *value); typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( - _In_ HMONITOR hmonitor, - _In_ MONITOR_DPI_TYPE dpiType, - _Out_ UINT *dpiX, - _Out_ UINT *dpiY); + _In_ HMONITOR hmonitor, + _In_ MONITOR_DPI_TYPE dpiType, + _Out_ UINT *dpiX, + _Out_ UINT *dpiY); // // LLWindowWin32 @@ -146,19 +146,19 @@ typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( void show_window_creation_error(const std::string& title) { - LL_WARNS("Window") << title << LL_ENDL; + LL_WARNS("Window") << title << LL_ENDL; } HGLRC SafeCreateContext(HDC &hdc) { - __try - { - return wglCreateContext(hdc); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - return NULL; - } + __try + { + return wglCreateContext(hdc); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return NULL; + } } GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) @@ -180,11 +180,11 @@ GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) //static BOOL LLWindowWin32::sIsClassRegistered = FALSE; -BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; -BOOL LLWindowWin32::sWinIMEOpened = FALSE; -HKL LLWindowWin32::sWinInputLocale = 0; -DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; -DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; +BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; +BOOL LLWindowWin32::sWinIMEOpened = FALSE; +HKL LLWindowWin32::sWinInputLocale = 0; +DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; +DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); // The following class LLWinImm delegates Windows IMM APIs. @@ -196,110 +196,110 @@ LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); class LLWinImm { public: - static bool isAvailable() { return true; } + static bool isAvailable() { return true; } public: - // Wrappers for IMM API. - static BOOL isIME(HKL hkl); - static HIMC getContext(HWND hwnd); - static BOOL releaseContext(HWND hwnd, HIMC himc); - static BOOL getOpenStatus(HIMC himc); - static BOOL setOpenStatus(HIMC himc, BOOL status); - static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); - static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); - static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); - static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); - static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); - static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); - static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); + // Wrappers for IMM API. + static BOOL isIME(HKL hkl); + static HIMC getContext(HWND hwnd); + static BOOL releaseContext(HWND hwnd, HIMC himc); + static BOOL getOpenStatus(HIMC himc); + static BOOL setOpenStatus(HIMC himc, BOOL status); + static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); + static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); + static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); + static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); + static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); + static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); + static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); }; -// static -BOOL LLWinImm::isIME(HKL hkl) -{ - return ImmIsIME(hkl); +// static +BOOL LLWinImm::isIME(HKL hkl) +{ + return ImmIsIME(hkl); } -// static -HIMC LLWinImm::getContext(HWND hwnd) +// static +HIMC LLWinImm::getContext(HWND hwnd) { - return ImmGetContext(hwnd); + return ImmGetContext(hwnd); } -//static -BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) -{ - return ImmReleaseContext(hwnd, himc); +//static +BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) +{ + return ImmReleaseContext(hwnd, himc); } -// static -BOOL LLWinImm::getOpenStatus(HIMC himc) -{ - return ImmGetOpenStatus(himc); +// static +BOOL LLWinImm::getOpenStatus(HIMC himc) +{ + return ImmGetOpenStatus(himc); } -// static -BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) -{ - return ImmSetOpenStatus(himc, status); +// static +BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) +{ + return ImmSetOpenStatus(himc, status); } -// static -BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) -{ - return ImmGetConversionStatus(himc, conversion, sentence); +// static +BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) +{ + return ImmGetConversionStatus(himc, conversion, sentence); } -// static -BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) -{ - return ImmSetConversionStatus(himc, conversion, sentence); +// static +BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) +{ + return ImmSetConversionStatus(himc, conversion, sentence); } -// static -BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - return ImmGetCompositionWindow(himc, form); +// static +BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + return ImmGetCompositionWindow(himc, form); } -// static -BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - return ImmSetCompositionWindow(himc, form); +// static +BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + return ImmSetCompositionWindow(himc, form); } -// static -LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) -{ - return ImmGetCompositionString(himc, index, data, length); +// static +LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) +{ + return ImmGetCompositionString(himc, index, data, length); } -// static -BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) -{ - return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); +// static +BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) +{ + return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); } -// static -BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) -{ - return ImmSetCompositionFont(himc, pFont); +// static +BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) +{ + return ImmSetCompositionFont(himc, pFont); } -// static -BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) -{ - return ImmSetCandidateWindow(himc, form); +// static +BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) +{ + return ImmSetCandidateWindow(himc, form); } -// static -BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) -{ - return ImmNotifyIME(himc, action, index, value); +// static +BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) +{ + return ImmNotifyIME(himc, action, index, value); } @@ -308,31 +308,31 @@ class LLMonitorInfo { public: - std::vector getResolutionsList() { return mResList; } + std::vector getResolutionsList() { return mResList; } - LLMonitorInfo() - { - EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); - } + LLMonitorInfo() + { + EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); + } private: - static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) - { - int monitor_width = lprcMonitor->right - lprcMonitor->left; - int monitor_height = lprcMonitor->bottom - lprcMonitor->top; - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); + static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) + { + int monitor_width = lprcMonitor->right - lprcMonitor->left; + int monitor_height = lprcMonitor->bottom - lprcMonitor->top; - LLMonitorInfo* pThis = reinterpret_cast(pData); - pThis->mResList.push_back(res); + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); - return TRUE; - } + LLMonitorInfo* pThis = reinterpret_cast(pData); + pThis->mResList.push_back(res); + + return TRUE; + } - std::vector mResList; + std::vector mResList; }; static LLMonitorInfo sMonitorInfo; @@ -363,7 +363,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // initialzie DXGI adapter (for querying available VRAM) void initDX(); - + // initialize D3D (if DXGI cannot be used) void initD3D(); @@ -437,28 +437,28 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, - U32 fsaa_samples, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + BOOL fullscreen, BOOL clearBg, + BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, + U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version) - : - LLWindow(callbacks, fullscreen, flags), - mMaxGLVersion(max_gl_version), + : + LLWindow(callbacks, fullscreen, flags), + mMaxGLVersion(max_gl_version), mMaxCores(max_cores) { sMainThreadId = LLThread::currentID(); mWindowThread = new LLWindowWin32Thread(); mWindowThread->mMaxVRAM = max_vram; - //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways - LoadLibrary(L"opengl32.dll"); - - + //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways + LoadLibrary(L"opengl32.dll"); + + if (mMaxCores != 0) { HANDLE hProcess = GetCurrentProcess(); @@ -530,76 +530,76 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, #endif - mFSAASamples = fsaa_samples; - mIconResource = gIconResource; - mOverrideAspectRatio = 0.f; - mNativeAspectRatio = 0.f; - mInputProcessingPaused = FALSE; - mPreeditor = NULL; - mKeyCharCode = 0; - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mhDC = NULL; - mhRC = NULL; - memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); - memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); - mCustomGammaSet = FALSE; - mWindowHandle = NULL; + mFSAASamples = fsaa_samples; + mIconResource = gIconResource; + mOverrideAspectRatio = 0.f; + mNativeAspectRatio = 0.f; + mInputProcessingPaused = FALSE; + mPreeditor = NULL; + mKeyCharCode = 0; + mKeyScanCode = 0; + mKeyVirtualKey = 0; + mhDC = NULL; + mhRC = NULL; + memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); + memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); + mCustomGammaSet = FALSE; + mWindowHandle = NULL; mRect = {0, 0, 0, 0}; mClientRect = {0, 0, 0, 0}; - - if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) - { - mMouseVanish = TRUE; - } - - // Initialize the keyboard - gKeyboard = new LLKeyboardWin32(); - gKeyboard->setCallbacks(callbacks); - - // Initialize the Drag and Drop functionality - mDragDrop = new LLDragDropWin32; - - // Initialize (boot strap) the Language text input management, - // based on the system's (user's) default settings. - allowLanguageTextInput(mPreeditor, FALSE); - - WNDCLASS wc; - RECT window_rect; - - // Set the window title - if (title.empty()) - { - mWindowTitle = new WCHAR[50]; - wsprintf(mWindowTitle, L"OpenGL Window"); - } - else - { - mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowTitle, title.c_str(), 255); - mWindowTitle[255] = 0; - } - - // Set the window class name - if (name.empty()) - { - mWindowClassName = new WCHAR[50]; - wsprintf(mWindowClassName, L"OpenGL Window"); - } - else - { - mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowClassName, name.c_str(), 255); - mWindowClassName[255] = 0; - } - - - // We're not clipping yet - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - - // Make an instance of our window then define the window class - mhInstance = GetModuleHandle(NULL); + + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) + { + mMouseVanish = TRUE; + } + + // Initialize the keyboard + gKeyboard = new LLKeyboardWin32(); + gKeyboard->setCallbacks(callbacks); + + // Initialize the Drag and Drop functionality + mDragDrop = new LLDragDropWin32; + + // Initialize (boot strap) the Language text input management, + // based on the system's (user's) default settings. + allowLanguageTextInput(mPreeditor, FALSE); + + WNDCLASS wc; + RECT window_rect; + + // Set the window title + if (title.empty()) + { + mWindowTitle = new WCHAR[50]; + wsprintf(mWindowTitle, L"OpenGL Window"); + } + else + { + mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowTitle, title.c_str(), 255); + mWindowTitle[255] = 0; + } + + // Set the window class name + if (name.empty()) + { + mWindowClassName = new WCHAR[50]; + wsprintf(mWindowClassName, L"OpenGL Window"); + } + else + { + mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowClassName, name.c_str(), 255); + mWindowClassName[255] = 0; + } + + + // We're not clipping yet + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + + // Make an instance of our window then define the window class + mhInstance = GetModuleHandle(NULL); // Init Direct Input - needed for joystick / Spacemouse @@ -616,199 +616,199 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, gDirectInput8 = di8_interface; } - mSwapMethod = SWAP_METHOD_UNDEFINED; - - // No WPARAM yet. - mLastSizeWParam = 0; - - // Windows GDI rects don't include rightmost pixel - window_rect.left = (long) 0; - window_rect.right = (long) width; - window_rect.top = (long) 0; - window_rect.bottom = (long) height; - - // Grab screen size to sanitize the window - S32 window_border_y = GetSystemMetrics(SM_CYBORDER); - S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); - S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - if (x < virtual_screen_x) x = virtual_screen_x; - if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; - - if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; - if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; - - if (!sIsClassRegistered) - { - // Force redraw when resized and create a private device context - - // Makes double click messages. - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; - - // Set message handler function - wc.lpfnWndProc = (WNDPROC) mainWindowProc; - - // unused - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - - wc.hInstance = mhInstance; - wc.hIcon = LoadIcon(mhInstance, mIconResource); - - // We will set the cursor ourselves - wc.hCursor = NULL; - - // background color is not used - if (clearBg) - { - wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - } - else - { - wc.hbrBackground = (HBRUSH) NULL; - } - - // we don't use windows menus - wc.lpszMenuName = NULL; - - wc.lpszClassName = mWindowClassName; - - if (!RegisterClass(&wc)) - { - OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), - mCallbacks->translateString("MBError"), OSMB_OK); - return; - } - sIsClassRegistered = TRUE; - } - - //----------------------------------------------------------------------- - // Get the current refresh rate - //----------------------------------------------------------------------- - - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); - } - else - { - current_refresh = 60; - } + mSwapMethod = SWAP_METHOD_UNDEFINED; + + // No WPARAM yet. + mLastSizeWParam = 0; + + // Windows GDI rects don't include rightmost pixel + window_rect.left = (long) 0; + window_rect.right = (long) width; + window_rect.top = (long) 0; + window_rect.bottom = (long) height; + + // Grab screen size to sanitize the window + S32 window_border_y = GetSystemMetrics(SM_CYBORDER); + S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); + S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); + S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + if (x < virtual_screen_x) x = virtual_screen_x; + if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; + + if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; + if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; + + if (!sIsClassRegistered) + { + // Force redraw when resized and create a private device context + + // Makes double click messages. + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + + // Set message handler function + wc.lpfnWndProc = (WNDPROC) mainWindowProc; + + // unused + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + wc.hInstance = mhInstance; + wc.hIcon = LoadIcon(mhInstance, mIconResource); + + // We will set the cursor ourselves + wc.hCursor = NULL; + + // background color is not used + if (clearBg) + { + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + } + else + { + wc.hbrBackground = (HBRUSH) NULL; + } + + // we don't use windows menus + wc.lpszMenuName = NULL; + + wc.lpszClassName = mWindowClassName; + + if (!RegisterClass(&wc)) + { + OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), + mCallbacks->translateString("MBError"), OSMB_OK); + return; + } + sIsClassRegistered = TRUE; + } + + //----------------------------------------------------------------------- + // Get the current refresh rate + //----------------------------------------------------------------------- + + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + DWORD current_refresh; + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); + } + else + { + current_refresh = 60; + } mRefreshRate = current_refresh; - //----------------------------------------------------------------------- - // Drop resolution and go fullscreen - // use a display mode with our desired size and depth, with a refresh - // rate as close at possible to the users' default - //----------------------------------------------------------------------- - if (mFullscreen) - { - BOOL success = FALSE; - DWORD closest_refresh = 0; - - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = TRUE; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } - - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - //success = FALSE; - - if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - success = FALSE; - } - else - { - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; - window_rect.right=width=dev_mode.dmPelsWidth; - window_rect.bottom=height=dev_mode.dmPelsHeight; - success = TRUE; - } - else - { - LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; - success = FALSE; - } - } - } - - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } - - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - // If it failed, we don't want to run fullscreen - if (success) - { - mFullscreen = TRUE; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; - - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; - } - else - { - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - std::map args; - args["[WIDTH]"] = llformat("%d", width); - args["[HEIGHT]"] = llformat ("%d", height); - OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), - mCallbacks->translateString("MBError"), OSMB_OK); - } - } - - // TODO: add this after resolving _WIN32_WINNT issue - // if (!fullscreen) - // { - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = mWindowHandle; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - // } + //----------------------------------------------------------------------- + // Drop resolution and go fullscreen + // use a display mode with our desired size and depth, with a refresh + // rate as close at possible to the users' default + //----------------------------------------------------------------------- + if (mFullscreen) + { + BOOL success = FALSE; + DWORD closest_refresh = 0; + + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = TRUE; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } + + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + //success = FALSE; + + if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + success = FALSE; + } + else + { + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; + window_rect.right=width=dev_mode.dmPelsWidth; + window_rect.bottom=height=dev_mode.dmPelsHeight; + success = TRUE; + } + else + { + LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; + success = FALSE; + } + } + } + + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } + + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + + // If it failed, we don't want to run fullscreen + if (success) + { + mFullscreen = TRUE; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + } + else + { + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + std::map args; + args["[WIDTH]"] = llformat("%d", width); + args["[HEIGHT]"] = llformat ("%d", height); + OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), + mCallbacks->translateString("MBError"), OSMB_OK); + } + } + + // TODO: add this after resolving _WIN32_WINNT issue + // if (!fullscreen) + // { + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = mWindowHandle; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + // } // SL-12971 dual GPU display DISPLAY_DEVICEA display_device; @@ -842,20 +842,20 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, LL_INFOS("Window") << "Total Display Devices: " << display_index << LL_ENDL; - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - LLCoordScreen windowPos(x,y); - LLCoordScreen windowSize(window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top); - if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) - { - return; - } - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + LLCoordScreen windowPos(x,y); + LLCoordScreen windowSize(window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top); + if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) + { + return; + } + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); mRawMouse.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC mRawMouse.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE @@ -864,56 +864,56 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse)); - // Initialize (boot strap) the Language text input management, - // based on the system's (or user's) default settings. - allowLanguageTextInput(NULL, FALSE); + // Initialize (boot strap) the Language text input management, + // based on the system's (or user's) default settings. + allowLanguageTextInput(NULL, FALSE); } LLWindowWin32::~LLWindowWin32() { - delete mDragDrop; + delete mDragDrop; - delete [] mWindowTitle; - mWindowTitle = NULL; + delete [] mWindowTitle; + mWindowTitle = NULL; - delete [] mSupportedResolutions; - mSupportedResolutions = NULL; + delete [] mSupportedResolutions; + mSupportedResolutions = NULL; + + delete [] mWindowClassName; + mWindowClassName = NULL; - delete [] mWindowClassName; - mWindowClassName = NULL; - delete mWindowThread; } void LLWindowWin32::show() { LL_DEBUGS("Window") << "Setting window to show" << LL_ENDL; - ShowWindow(mWindowHandle, SW_SHOW); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); + ShowWindow(mWindowHandle, SW_SHOW); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); } void LLWindowWin32::hide() { - setMouseClipping(FALSE); - ShowWindow(mWindowHandle, SW_HIDE); + setMouseClipping(FALSE); + ShowWindow(mWindowHandle, SW_HIDE); } //virtual void LLWindowWin32::minimize() { - setMouseClipping(FALSE); - showCursor(); - ShowWindow(mWindowHandle, SW_MINIMIZE); + setMouseClipping(FALSE); + showCursor(); + ShowWindow(mWindowHandle, SW_MINIMIZE); } //virtual void LLWindowWin32::restore() { - ShowWindow(mWindowHandle, SW_RESTORE); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); + ShowWindow(mWindowHandle, SW_RESTORE); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); } // See SL-12170 @@ -942,88 +942,88 @@ bool destroy_window_handler(HWND hWnd) // Usually called from LLWindowManager::destroyWindow() void LLWindowWin32::close() { - LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; - // Is window is already closed? - if (!mWindowHandle) - { - return; - } - - mDragDrop->reset(); - - - // Go back to screen mode written in the registry. - if (mFullscreen) - { - resetDisplayResolution(); - } - - // Make sure cursor is visible and we haven't mangled the clipping state. - showCursor(); - setMouseClipping(FALSE); - if (gKeyboard) - { - gKeyboard->resetKeys(); - } - - // Clean up remaining GL state - if (gGLManager.mInited) - { - LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL; - gGLManager.shutdownGL(); - } - - LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; - } - - // Restore gamma to the system values. - restoreGamma(); - - LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; + LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; + // Is window is already closed? + if (!mWindowHandle) + { + return; + } + + mDragDrop->reset(); + + + // Go back to screen mode written in the registry. + if (mFullscreen) + { + resetDisplayResolution(); + } + + // Make sure cursor is visible and we haven't mangled the clipping state. + showCursor(); + setMouseClipping(FALSE); + if (gKeyboard) + { + gKeyboard->resetKeys(); + } + + // Clean up remaining GL state + if (gGLManager.mInited) + { + LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL; + gGLManager.shutdownGL(); + } + + LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } + + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } + + mhRC = NULL; + } + + // Restore gamma to the system values. + restoreGamma(); + + LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; mhDC = NULL; mWindowHandle = NULL; - + mWindowThread->wakeAndDestroy(); } BOOL LLWindowWin32::isValid() { - return (mWindowHandle != NULL); + return (mWindowHandle != NULL); } BOOL LLWindowWin32::getVisible() { - return (mWindowHandle && IsWindowVisible(mWindowHandle)); + return (mWindowHandle && IsWindowVisible(mWindowHandle)); } BOOL LLWindowWin32::getMinimized() { - return (mWindowHandle && IsIconic(mWindowHandle)); + return (mWindowHandle && IsIconic(mWindowHandle)); } BOOL LLWindowWin32::getMaximized() { - return (mWindowHandle && IsZoomed(mWindowHandle)); + return (mWindowHandle && IsZoomed(mWindowHandle)); } BOOL LLWindowWin32::maximize() { - BOOL success = FALSE; - if (!mWindowHandle) return success; + BOOL success = FALSE; + if (!mWindowHandle) return success; mWindowThread->post([=] { @@ -1042,52 +1042,52 @@ BOOL LLWindowWin32::maximize() BOOL LLWindowWin32::getFullscreen() { - return mFullscreen; + return mFullscreen; } BOOL LLWindowWin32::getPosition(LLCoordScreen *position) { position->mX = mRect.left; - position->mY = mRect.top; - return TRUE; + position->mY = mRect.top; + return TRUE; } BOOL LLWindowWin32::getSize(LLCoordScreen *size) { - size->mX = mRect.right - mRect.left; - size->mY = mRect.bottom - mRect.top; - return TRUE; + size->mX = mRect.right - mRect.left; + size->mY = mRect.bottom - mRect.top; + return TRUE; } BOOL LLWindowWin32::getSize(LLCoordWindow *size) { - size->mX = mClientRect.right - mClientRect.left; - size->mY = mClientRect.bottom - mClientRect.top; - return TRUE; + size->mX = mClientRect.right - mClientRect.left; + size->mY = mClientRect.bottom - mClientRect.top; + return TRUE; } BOOL LLWindowWin32::setPosition(const LLCoordScreen position) { - LLCoordScreen size; + LLCoordScreen size; - if (!mWindowHandle) - { - return FALSE; - } - getSize(&size); - moveWindow(position, size); - return TRUE; + if (!mWindowHandle) + { + return FALSE; + } + getSize(&size); + moveWindow(position, size); + return TRUE; } BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) { - LLCoordScreen position; + LLCoordScreen position; - getPosition(&position); - if (!mWindowHandle) - { - return FALSE; - } + getPosition(&position); + if (!mWindowHandle) + { + return FALSE; + } mWindowThread->post([=]() { @@ -1101,33 +1101,33 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) } }); - moveWindow(position, size); - return TRUE; + moveWindow(position, size); + return TRUE; } BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) { - RECT window_rect = {0, 0, size.mX, size.mY }; - DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dw_style = WS_OVERLAPPEDWINDOW; + RECT window_rect = {0, 0, size.mX, size.mY }; + DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dw_style = WS_OVERLAPPEDWINDOW; AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); - return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); + return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); } // changing fullscreen resolution BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BOOL enable_vsync, const LLCoordScreen* const posp) { //called from main thread - GLuint pixel_format; + GLuint pixel_format; DEVMODE dev_mode; ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - DWORD dw_ex_style; - DWORD dw_style; - RECT window_rect = { 0, 0, 0, 0 }; + DWORD current_refresh; + DWORD dw_ex_style; + DWORD dw_style; + RECT window_rect = { 0, 0, 0, 0 }; S32 width = size.mX; S32 height = size.mY; BOOL auto_show = FALSE; @@ -1203,7 +1203,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); } - // Keep a copy of the actual current device mode in case we minimize + // Keep a copy of the actual current device mode in case we minimize // and change the screen resolution. JC EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); @@ -1222,7 +1222,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO << LL_ENDL; window_rect.left = (long)0; - window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel + window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel window_rect.top = (long)0; window_rect.bottom = (long)height; dw_ex_style = WS_EX_APPWINDOW; @@ -1249,7 +1249,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO { mFullscreen = FALSE; window_rect.left = (long)(posp ? posp->mX : 0); - window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel + window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel window_rect.top = (long)(posp ? posp->mY : 0); window_rect.bottom = (long)height + window_rect.top; // Window with an edge @@ -1258,330 +1258,330 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO } - // don't post quit messages when destroying old windows - mPostQuit = FALSE; + // don't post quit messages when destroying old windows + mPostQuit = FALSE; + + + // create window + LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left + << " Y: " << window_rect.top + << " Width: " << (window_rect.right - window_rect.left) + << " Height: " << (window_rect.bottom - window_rect.top) + << " Fullscreen: " << mFullscreen + << LL_ENDL; + + recreateWindow(window_rect, dw_ex_style, dw_style); + + if (mWindowHandle) + { + LL_INFOS("Window") << "window is created." << LL_ENDL ; + } + else + { + LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; + } + + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + static PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + BITS_PER_PIXEL, + 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused + 8, // alpha bits + 0, // alpha shift + 0, // accum bits + 0, 0, 0, 0, // accum RGBA + 24, // depth bits + 8, // stencil bits, avi added for stencil test + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + if (!mhDC) + { + close(); + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return FALSE; + } + + LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; + + try + { + // Looks like ChoosePixelFormat can crash in case of faulty driver + if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd))) + { + LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL; + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash + LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; + LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; + LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; + LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; + LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; + LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; + LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; + LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; + LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + + if (!(mhRC = SafeCreateContext(mhDC))) + { + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + if (!wglMakeCurrent(mhDC, mhRC)) + { + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; + + gGLManager.initWGL(); + + if (wglChoosePixelFormatARB) + { + // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we + // can get exactly what we want. + GLint attrib_list[256]; + S32 cur_attrib = 0; + + attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; + attrib_list[cur_attrib++] = 24; + + //attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) + //attrib_list[cur_attrib++] = 8; + + attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; + attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; + + attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; + attrib_list[cur_attrib++] = 24; + + attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; + attrib_list[cur_attrib++] = 0; + + U32 end_attrib = 0; + if (mFSAASamples > 0) + { + end_attrib = cur_attrib; + attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; + attrib_list[cur_attrib++] = mFSAASamples; + } + + // End the list + attrib_list[cur_attrib++] = 0; + + GLint pixel_formats[256]; + U32 num_formats = 0; + + // First we try and get a 32 bit depth pixel format + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + + while(!result && mFSAASamples > 0) + { + LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; + + mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing + if(mFSAASamples < 2) + { + mFSAASamples = 0 ; + } + + if (mFSAASamples > 0) + { + attrib_list[end_attrib + 3] = mFSAASamples; + } + else + { + cur_attrib = end_attrib ; + end_attrib = 0 ; + attrib_list[cur_attrib++] = 0 ; //end + } + result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + + if(result) + { + LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; + } + } + + if (!result) + { + LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; + + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); + return FALSE; + } + if (!num_formats) + { + if (end_attrib > 0) + { + LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; + attrib_list[end_attrib] = 0; - // create window - LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left - << " Y: " << window_rect.top - << " Width: " << (window_rect.right - window_rect.left) - << " Height: " << (window_rect.bottom - window_rect.top) - << " Fullscreen: " << mFullscreen - << LL_ENDL; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); + return FALSE; + } + } - recreateWindow(window_rect, dw_ex_style, dw_style); - - if (mWindowHandle) - { - LL_INFOS("Window") << "window is created." << LL_ENDL ; - } - else - { - LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; - } - - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - static PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, - BITS_PER_PIXEL, - 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused - 8, // alpha bits - 0, // alpha shift - 0, // accum bits - 0, 0, 0, 0, // accum RGBA - 24, // depth bits - 8, // stencil bits, avi added for stencil test - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - if (!mhDC) - { - close(); - OSMessageBox(mCallbacks->translateString("MBDevContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; - } - - LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; + if (!num_formats) + { + LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; + // Try 24-bit format + attrib_list[1] = 24; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); + return FALSE; + } - try - { - // Looks like ChoosePixelFormat can crash in case of faulty driver - if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd))) - { - LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL; - OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; + if (!num_formats) + { + LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; + attrib_list[1] = 16; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result || !num_formats) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); + return FALSE; + } + } + } + + LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; } - } - catch (...) - { - LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); - OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; + LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash - LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; - LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; - LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; - LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; - LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; - LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; - LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; - LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; - LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } + S32 swap_method = 0; + S32 cur_format = 0; +const S32 max_format = (S32)num_formats - 1; + GLint swap_query = WGL_SWAP_METHOD_ARB; + + // SL-14705 Fix name tags showing in front of objects with AMD GPUs. + // On AMD hardware we need to iterate from the first pixel format to the end. + // Spec: + // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt + while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) + { + if (swap_method == WGL_SWAP_UNDEFINED_ARB) + { + break; + } + else if (cur_format >= max_format) + { + cur_format = 0; + break; + } + + ++cur_format; + } + pixel_format = pixel_formats[cur_format]; - if (!(mhRC = SafeCreateContext(mhDC))) - { - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; - - gGLManager.initWGL(); - - if (wglChoosePixelFormatARB) - { - // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we - // can get exactly what we want. - GLint attrib_list[256]; - S32 cur_attrib = 0; - - attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - //attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) - //attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; - attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; - - attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; - attrib_list[cur_attrib++] = 0; - - U32 end_attrib = 0; - if (mFSAASamples > 0) - { - end_attrib = cur_attrib; - attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; - attrib_list[cur_attrib++] = mFSAASamples; - } - - // End the list - attrib_list[cur_attrib++] = 0; - - GLint pixel_formats[256]; - U32 num_formats = 0; - - // First we try and get a 32 bit depth pixel format - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - - while(!result && mFSAASamples > 0) - { - LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; - - mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing - if(mFSAASamples < 2) - { - mFSAASamples = 0 ; - } - - if (mFSAASamples > 0) - { - attrib_list[end_attrib + 3] = mFSAASamples; - } - else - { - cur_attrib = end_attrib ; - end_attrib = 0 ; - attrib_list[cur_attrib++] = 0 ; //end - } - result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - - if(result) - { - LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; - } - } - - if (!result) - { - LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; - - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); - return FALSE; - } - - if (!num_formats) - { - if (end_attrib > 0) - { - LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; - attrib_list[end_attrib] = 0; - - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); - return FALSE; - } - } - - if (!num_formats) - { - LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; - // Try 24-bit format - attrib_list[1] = 24; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); - return FALSE; - } - - if (!num_formats) - { - LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; - attrib_list[1] = 16; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result || !num_formats) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); - return FALSE; - } - } - } - - LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; - } - - LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; - - S32 swap_method = 0; - S32 cur_format = 0; -const S32 max_format = (S32)num_formats - 1; - GLint swap_query = WGL_SWAP_METHOD_ARB; - - // SL-14705 Fix name tags showing in front of objects with AMD GPUs. - // On AMD hardware we need to iterate from the first pixel format to the end. - // Spec: - // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt - while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) - { - if (swap_method == WGL_SWAP_UNDEFINED_ARB) - { - break; - } - else if (cur_format >= max_format) - { - cur_format = 0; - break; - } - - ++cur_format; - } - - pixel_format = pixel_formats[cur_format]; - - if (mhDC != 0) // Does The Window Have A Device Context? - { - wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero - if (mhRC != 0) // Does The Window Have A Rendering Context? - { - wglDeleteContext (mhRC); // Release The Rendering Context - mhRC = 0; // Zero The Rendering Context - } - } + if (mhDC != 0) // Does The Window Have A Device Context? + { + wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero + if (mhRC != 0) // Does The Window Have A Rendering Context? + { + wglDeleteContext (mhRC); // Release The Rendering Context + mhRC = 0; // Zero The Rendering Context + } + } // will release and recreate mhDC, mWindowHandle - recreateWindow(window_rect, dw_ex_style, dw_style); - + recreateWindow(window_rect, dw_ex_style, dw_style); + RECT rect; RECT client_rect; //initialize immediately on main thread @@ -1592,112 +1592,112 @@ const S32 max_format = (S32)num_formats - 1; mClientRect = client_rect; }; - if (mWindowHandle) - { - LL_INFOS("Window") << "recreate window done." << LL_ENDL ; - } - else - { - // Note: if value is NULL GetDC retrieves the DC for the entire screen. - LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; - } - - if (!mhDC) - { - OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) - { - switch (swap_method) - { - case WGL_SWAP_EXCHANGE_ARB: - mSwapMethod = SWAP_METHOD_EXCHANGE; - LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; - break; - case WGL_SWAP_COPY_ARB: - mSwapMethod = SWAP_METHOD_COPY; - LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; - break; - case WGL_SWAP_UNDEFINED_ARB: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; - break; - default: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; - break; - } - } - } - else - { - LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return FALSE; - } - - LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) - << " Alpha Bits " << S32(pfd.cAlphaBits) - << " Depth Bits " << S32(pfd.cDepthBits) - << LL_ENDL; - - mhRC = 0; - if (wglCreateContextAttribsARB) - { //attempt to create a specific versioned context + if (mWindowHandle) + { + LL_INFOS("Window") << "recreate window done." << LL_ENDL ; + } + else + { + // Note: if value is NULL GetDC retrieves the DC for the entire screen. + LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; + } + + if (!mhDC) + { + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) + { + switch (swap_method) + { + case WGL_SWAP_EXCHANGE_ARB: + mSwapMethod = SWAP_METHOD_EXCHANGE; + LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; + break; + case WGL_SWAP_COPY_ARB: + mSwapMethod = SWAP_METHOD_COPY; + LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; + break; + case WGL_SWAP_UNDEFINED_ARB: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; + break; + default: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; + break; + } + } + } + else + { + LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; + } + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return FALSE; + } + + LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) + << " Alpha Bits " << S32(pfd.cAlphaBits) + << " Depth Bits " << S32(pfd.cDepthBits) + << LL_ENDL; + + mhRC = 0; + if (wglCreateContextAttribsARB) + { //attempt to create a specific versioned context mhRC = (HGLRC) createSharedContext(); if (!mhRC) { return FALSE; } - } + } - if (!wglMakeCurrent(mhDC, mhRC)) - { - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); + if (!wglMakeCurrent(mhDC, mhRC)) + { + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } + return FALSE; + } - if (!gGLManager.initGL()) - { - OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); + if (!gGLManager.initGL()) + { + OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; - } - - // Disable vertical sync for swap + return FALSE; + } + + // Disable vertical sync for swap toggleVSync(enable_vsync); - SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); + SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); + + // register this window as handling drag/drop events from the OS + DragAcceptFiles( mWindowHandle, TRUE ); - // register this window as handling drag/drop events from the OS - DragAcceptFiles( mWindowHandle, TRUE ); + mDragDrop->init( mWindowHandle ); - mDragDrop->init( mWindowHandle ); - - //register joystick timer callback - SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer + //register joystick timer callback + SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer - // ok to post quit messages now - mPostQuit = TRUE; + // ok to post quit messages now + mPostQuit = TRUE; // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 @@ -1706,17 +1706,17 @@ const S32 max_format = (S32)num_formats - 1; mWindowThread->glReady(); }); - if (auto_show) - { - show(); - glClearColor(0.0f, 0.0f, 0.0f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - swapBuffers(); - } + if (auto_show) + { + show(); + glClearColor(0.0f, 0.0f, 0.0f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + swapBuffers(); + } LL_PROFILER_GPU_CONTEXT; - return TRUE; + return TRUE; } void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) @@ -1771,10 +1771,10 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw windowClassName, windowTitle, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height NULL, NULL, hInstance, @@ -1793,7 +1793,7 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw self->mWindowHandleThrd = handle; self->mhDCThrd = GetDC(handle); } - + updateWindowRect(); // It's important to wake up the future either way. @@ -1909,22 +1909,22 @@ void LLWindowWin32::toggleVSync(bool enable_vsync) void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) { - if( mIsMouseClipping ) - { - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - ClipCursor( &client_rect_in_screen_space ); - } - } - - // if the window was already maximized, MoveWindow seems to still set the maximized flag even if - // the window is smaller than maximized. - // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). - - // THIS CAUSES DEV-15484 and DEV-15949 - //ShowWindow(mWindowHandle, SW_RESTORE); - // NOW we can call MoveWindow + if( mIsMouseClipping ) + { + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + ClipCursor( &client_rect_in_screen_space ); + } + } + + // if the window was already maximized, MoveWindow seems to still set the maximized flag even if + // the window is smaller than maximized. + // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). + + // THIS CAUSES DEV-15484 and DEV-15949 + //ShowWindow(mWindowHandle, SW_RESTORE); + // NOW we can call MoveWindow mWindowThread->post([=]() { MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); @@ -1979,7 +1979,7 @@ BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) } *position = mCursorPosition; - return TRUE; + return TRUE; } BOOL LLWindowWin32::getCursorDelta(LLCoordCommon* delta) @@ -2006,8 +2006,8 @@ void LLWindowWin32::hideCursor() } }); - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; + mCursorHidden = TRUE; + mHideCursorPermanent = TRUE; } void LLWindowWin32::showCursor() @@ -2015,7 +2015,7 @@ void LLWindowWin32::showCursor() LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; ASSERT_MAIN_THREAD(); - + mWindowThread->post([=]() { // makes sure the cursor shows up @@ -2025,103 +2025,103 @@ void LLWindowWin32::showCursor() } }); - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; + mCursorHidden = FALSE; + mHideCursorPermanent = FALSE; } void LLWindowWin32::showCursorFromMouseMove() { - if (!mHideCursorPermanent) - { - showCursor(); - } + if (!mHideCursorPermanent) + { + showCursor(); + } } void LLWindowWin32::hideCursorUntilMouseMove() { - if (!mHideCursorPermanent && mMouseVanish) - { - hideCursor(); - mHideCursorPermanent = FALSE; - } + if (!mHideCursorPermanent && mMouseVanish) + { + hideCursor(); + mHideCursorPermanent = FALSE; + } } BOOL LLWindowWin32::isCursorHidden() { - return mCursorHidden; + return mCursorHidden; } HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) { - return (HCURSOR)LoadImage(mhInstance, - name, - IMAGE_CURSOR, - 0, // default width - 0, // default height - LR_DEFAULTCOLOR); + return (HCURSOR)LoadImage(mhInstance, + name, + IMAGE_CURSOR, + 0, // default width + 0, // default height + LR_DEFAULTCOLOR); } void LLWindowWin32::initCursors() { - mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); - mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); - mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); - mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); - mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); - mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); - mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); - mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); - mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); - mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL); - mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); - mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); - - HMODULE module = GetModuleHandle(NULL); - mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); - mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); - mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); - mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); - mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); - mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); - mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); - mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); - mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); - mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); - mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); - mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); - mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); - mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); - mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); - mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); - mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); - mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT")); - mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); - mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); - mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); - mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); - mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); - mCursor[ UI_CURSOR_TOOLPATHFINDING ] = LoadCursor(module, TEXT("TOOLPATHFINDING")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTARTADD")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTART")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHEND")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHENDADD")); - mCursor[ UI_CURSOR_TOOLNO ] = LoadCursor(module, TEXT("TOOLNO")); - - // Color cursors - mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); - mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); - mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); - - // Note: custom cursors that are not found make LoadCursor() return NULL. - for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) - { - if( !mCursor[i] ) - { - mCursor[i] = LoadCursor(NULL, IDC_ARROW); - } - } + mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); + mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); + mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); + mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); + mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); + mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); + mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); + mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); + mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); + mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL); + mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); + mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); + + HMODULE module = GetModuleHandle(NULL); + mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); + mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); + mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); + mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); + mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); + mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); + mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); + mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); + mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); + mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); + mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); + mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); + mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); + mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); + mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); + mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); + mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); + mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT")); + mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); + mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); + mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); + mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); + mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); + mCursor[ UI_CURSOR_TOOLPATHFINDING ] = LoadCursor(module, TEXT("TOOLPATHFINDING")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTARTADD")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTART")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHEND")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHENDADD")); + mCursor[ UI_CURSOR_TOOLNO ] = LoadCursor(module, TEXT("TOOLNO")); + + // Color cursors + mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); + mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); + mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); + + // Note: custom cursors that are not found make LoadCursor() return NULL. + for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) + { + if( !mCursor[i] ) + { + mCursor[i] = LoadCursor(NULL, IDC_ARROW); + } + } } @@ -2130,43 +2130,43 @@ void LLWindowWin32::updateCursor() { ASSERT_MAIN_THREAD(); LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - - if( mCurrentCursor != mNextCursor ) - { - mCurrentCursor = mNextCursor; + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + + if( mCurrentCursor != mNextCursor ) + { + mCurrentCursor = mNextCursor; auto nextCursor = mCursor[mNextCursor]; mWindowThread->post([=]() { SetCursor(nextCursor); }); - } + } } ECursorType LLWindowWin32::getCursor() const { - return mCurrentCursor; + return mCurrentCursor; } void LLWindowWin32::captureMouse() { - SetCapture(mWindowHandle); + SetCapture(mWindowHandle); } void LLWindowWin32::releaseMouse() { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - ReleaseCapture(); + ReleaseCapture(); } void LLWindowWin32::delayInputProcessing() { - mInputProcessingPaused = TRUE; + mInputProcessingPaused = TRUE; } @@ -2190,7 +2190,7 @@ void LLWindowWin32::gatherInput() LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage"); kickWindowThread(); } - + while (mWindowThread->mMessageQueue.tryPopBack(msg)) { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue"); @@ -2234,7 +2234,7 @@ void LLWindowWin32::gatherInput() LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move"); mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask); } - + mLastCursorPosition = mCursorPosition; { @@ -2247,9 +2247,9 @@ void LLWindowWin32::gatherInput() } } - mInputProcessingPaused = FALSE; + mInputProcessingPaused = FALSE; - updateCursor(); + updateCursor(); } static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); @@ -2296,9 +2296,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ switch (u_msg) { - RECT update_rect; - S32 update_width; - S32 update_height; + RECT update_rect; + S32 update_width; + S32 update_height; case WM_TIMER: { @@ -2313,7 +2313,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) { WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - + return TRUE; } break; @@ -2374,7 +2374,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ if (window_imp->mFullscreen) { - // When we run fullscreen, restoring or minimizing the app needs + // When we run fullscreen, restoring or minimizing the app needs // to switch the screen resolution if (activating) { @@ -2410,7 +2410,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->interruptLanguageTextInput(); } }); - + break; } @@ -2488,7 +2488,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ gKeyboard->handleKeyDown(w_param, mask); }); - if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress break; } case WM_SYSKEYUP: @@ -2510,7 +2510,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ gKeyboard->handleKeyUp(w_param, mask); } }); - if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress break; } case WM_IME_SETCONTEXT: @@ -2583,7 +2583,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // it is worth trying. The good old WM_CHAR works just fine even for supplementary // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's // by ourselves. It is not that tough. -- Alissa Sabre @ SL - + // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, // we *did* processed the event, so I believe we should not pass it to DefWindowProc... window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); @@ -2611,12 +2611,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->postMouseButtonEvent([=]() { sHandleLeftMouseUp = true; - + if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); } - + MASK mask = gKeyboard->currentMask(TRUE); auto gl_coord = window_imp->mCursorPosition.convert(); window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); @@ -2663,7 +2663,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } sHandleDoubleClick = true; - + MASK mask = gKeyboard->currentMask(TRUE); // generate move event to update mouse coordinates window_imp->mCursorPosition = window_coord; @@ -2711,7 +2711,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; case WM_MBUTTONDOWN: - // case WM_MBUTTONDBLCLK: + // case WM_MBUTTONDBLCLK: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN"); { @@ -2759,7 +2759,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); }); - + } break; @@ -2784,7 +2784,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL"); static short z_delta = 0; - RECT client_rect; + RECT client_rect; // eat scroll events that occur outside our window, since we use mouse position to direct scroll // instead of keyboard focus @@ -2827,12 +2827,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { window_imp->mCallbacks->handleMouseLeave(window_imp); - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = h_wnd; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = h_wnd; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); return 0; } */ @@ -2841,7 +2841,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL"); static short h_delta = 0; - RECT client_rect; + RECT client_rect; // eat scroll events that occur outside our window, since we use mouse position to direct scroll // instead of keyboard focus @@ -2876,7 +2876,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MOUSEMOVE: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE"); - // DO NOT use mouse event queue for move events to ensure cursor position is updated + // DO NOT use mouse event queue for move events to ensure cursor position is updated // when button events are handled WINDOW_IMP_POST( { @@ -2908,12 +2908,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE"); window_imp->updateWindowRect(); - // There's an odd behavior with WM_SIZE that I would call a bug. If + // There's an odd behavior with WM_SIZE that I would call a bug. If // the window is maximized, and you call MoveWindow() with a size smaller - // than a maximized window, it ends up sending WM_SIZE with w_param set + // than a maximized window, it ends up sending WM_SIZE with w_param set // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. - // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see - // LLWindowWin32::moveWindow in this file). + // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see + // LLWindowWin32::moveWindow in this file). // If we are now restored, but we weren't before, this // means that the window was un-minimized. @@ -2957,7 +2957,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ S32 new_width = lprc_new_scale->right - lprc_new_scale->left; S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; WINDOW_IMP_POST(window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height)); - + SetWindowPos(h_wnd, HWND_TOP, lprc_new_scale->left, @@ -2965,7 +2965,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ new_width, new_height, SWP_NOZORDER | SWP_NOACTIVATE); - + return 0; } @@ -3015,17 +3015,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } break; - + case WM_INPUT: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT"); - + UINT dwSize = 0; GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); llassert(dwSize < 1024); U8 lpb[1024]; - + if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) { RAWINPUT* raw = (RAWINPUT*)lpb; @@ -3121,175 +3121,175 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) { - S32 client_height; - RECT client_rect; - LLCoordWindow window_position; + S32 client_height; + RECT client_rect; + LLCoordWindow window_position; - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == to) - { - return FALSE; - } + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == to) + { + return FALSE; + } - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; + to->mX = from.mX; + client_height = client_rect.bottom - client_rect.top; + to->mY = client_height - from.mY - 1; - return TRUE; + return TRUE; } BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) { - S32 client_height; - RECT client_rect; + S32 client_height; + RECT client_rect; - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == to) - { - return FALSE; - } + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + NULL == to) + { + return FALSE; + } - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; + to->mX = from.mX; + client_height = client_rect.bottom - client_rect.top; + to->mY = client_height - from.mY - 1; - return TRUE; + return TRUE; } BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - POINT mouse_point; +{ + POINT mouse_point; - mouse_point.x = from.mX; - mouse_point.y = from.mY; - BOOL result = ScreenToClient(mWindowHandle, &mouse_point); + mouse_point.x = from.mX; + mouse_point.y = from.mY; + BOOL result = ScreenToClient(mWindowHandle, &mouse_point); - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } - return result; + return result; } BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) { - POINT mouse_point; + POINT mouse_point; - mouse_point.x = from.mX; - mouse_point.y = from.mY; - BOOL result = ClientToScreen(mWindowHandle, &mouse_point); + mouse_point.x = from.mX; + mouse_point.y = from.mY; + BOOL result = ClientToScreen(mWindowHandle, &mouse_point); - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } - return result; + return result; } BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - if (!mWindowHandle || (NULL == to)) - { - return FALSE; - } + if (!mWindowHandle || (NULL == to)) + { + return FALSE; + } - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return TRUE; + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return TRUE; } BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - if (!mWindowHandle || (NULL == to)) - { - return FALSE; - } + if (!mWindowHandle || (NULL == to)) + { + return FALSE; + } - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return TRUE; + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return TRUE; } BOOL LLWindowWin32::isClipboardTextAvailable() { - return IsClipboardFormatAvailable(CF_UNICODETEXT); + return IsClipboardFormatAvailable(CF_UNICODETEXT); } BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) { - BOOL success = FALSE; + BOOL success = FALSE; - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) - { - if (OpenClipboard(mWindowHandle)) - { - HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); - if (h_data) - { - WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); - if (utf16str) - { - dst = utf16str_to_wstring(utf16str); - LLWStringUtil::removeWindowsCR(dst); - GlobalUnlock(h_data); - success = TRUE; - } - } - CloseClipboard(); - } - } + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + if (OpenClipboard(mWindowHandle)) + { + HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); + if (h_data) + { + WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); + if (utf16str) + { + dst = utf16str_to_wstring(utf16str); + LLWStringUtil::removeWindowsCR(dst); + GlobalUnlock(h_data); + success = TRUE; + } + } + CloseClipboard(); + } + } - return success; + return success; } BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) { - BOOL success = FALSE; + BOOL success = FALSE; - if (OpenClipboard(mWindowHandle)) - { - EmptyClipboard(); + if (OpenClipboard(mWindowHandle)) + { + EmptyClipboard(); - // Provide a copy of the data in Unicode format. - LLWString sanitized_string(wstr); - LLWStringUtil::addCRLF(sanitized_string); - llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); - const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); + // Provide a copy of the data in Unicode format. + LLWString sanitized_string(wstr); + LLWStringUtil::addCRLF(sanitized_string); + llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); + const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); - // Memory is allocated and then ownership of it is transfered to the system. - HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); - if (hglobal_copy_utf16) - { - WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); - if (copy_utf16) - { - memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ - GlobalUnlock(hglobal_copy_utf16); + // Memory is allocated and then ownership of it is transfered to the system. + HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); + if (hglobal_copy_utf16) + { + WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); + if (copy_utf16) + { + memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ + GlobalUnlock(hglobal_copy_utf16); - if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) - { - success = TRUE; - } - } - } + if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) + { + success = TRUE; + } + } + } - CloseClipboard(); - } + CloseClipboard(); + } - return success; + return success; } // Constrains the mouse to the window. @@ -3297,32 +3297,32 @@ void LLWindowWin32::setMouseClipping( BOOL b ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; ASSERT_MAIN_THREAD(); - if( b != mIsMouseClipping ) - { - BOOL success = FALSE; - - if( b ) - { - GetClipCursor( &mOldMouseClip ); - - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - success = ClipCursor( &client_rect_in_screen_space ); - } - } - else - { - // Must restore the old mouse clip, which may be set by another window. - success = ClipCursor( &mOldMouseClip ); - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - } - - if( success ) - { - mIsMouseClipping = b; - } - } + if( b != mIsMouseClipping ) + { + BOOL success = FALSE; + + if( b ) + { + GetClipCursor( &mOldMouseClip ); + + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + success = ClipCursor( &client_rect_in_screen_space ); + } + } + else + { + // Must restore the old mouse clip, which may be set by another window. + success = ClipCursor( &mOldMouseClip ); + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + } + + if( success ) + { + mIsMouseClipping = b; + } + } } BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) @@ -3371,29 +3371,29 @@ void LLWindowWin32::flashIcon(F32 seconds) F32 LLWindowWin32::getGamma() { - return mCurrentGamma; + return mCurrentGamma; } BOOL LLWindowWin32::restoreGamma() { ASSERT_MAIN_THREAD(); - if (mCustomGammaSet != FALSE) - { + if (mCustomGammaSet != FALSE) + { LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; - mCustomGammaSet = FALSE; - return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); - } - return TRUE; + mCustomGammaSet = FALSE; + return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); + } + return TRUE; } BOOL LLWindowWin32::setGamma(const F32 gamma) { ASSERT_MAIN_THREAD(); - mCurrentGamma = gamma; + mCurrentGamma = gamma; - //Get the previous gamma ramp to restore later. - if (mCustomGammaSet == FALSE) - { + //Get the previous gamma ramp to restore later. + if (mCustomGammaSet == FALSE) + { if (!gGLManager.mIsIntel) // skip for Intel GPUs (see SL-11341) { LL_DEBUGS("Window") << "Getting the previous gamma ramp to restore later" << LL_ENDL; @@ -3403,192 +3403,192 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) return FALSE; } } - mCustomGammaSet = TRUE; - } + mCustomGammaSet = TRUE; + } - LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; + LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; - for ( int i = 0; i < 256; ++i ) - { - int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); + for ( int i = 0; i < 256; ++i ) + { + int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); - int value = mult * i; + int value = mult * i; - if ( value > 0xffff ) - value = 0xffff; + if ( value > 0xffff ) + value = 0xffff; - mCurrentGammaRamp[0][i] = - mCurrentGammaRamp[1][i] = - mCurrentGammaRamp[2][i] = (WORD) value; - }; + mCurrentGammaRamp[0][i] = + mCurrentGammaRamp[1][i] = + mCurrentGammaRamp[2][i] = (WORD) value; + }; - return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); + return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); } void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) { ASSERT_MAIN_THREAD(); - mFSAASamples = fsaa_samples; + mFSAASamples = fsaa_samples; } U32 LLWindowWin32::getFSAASamples() { - return mFSAASamples; + return mFSAASamples; } LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { ASSERT_MAIN_THREAD(); - if (!mSupportedResolutions) - { - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - - mNumSupportedResolutions = 0; - for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && - dev_mode.dmPelsWidth >= 800 && - dev_mode.dmPelsHeight >= 600) - { - BOOL resolution_exists = FALSE; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && - mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) - { - resolution_exists = TRUE; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; - mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; - mNumSupportedResolutions++; - } - } - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; + if (!mSupportedResolutions) + { + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + + mNumSupportedResolutions = 0; + for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && + dev_mode.dmPelsWidth >= 800 && + dev_mode.dmPelsHeight >= 600) + { + BOOL resolution_exists = FALSE; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && + mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) + { + resolution_exists = TRUE; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; + mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; + mNumSupportedResolutions++; + } + } + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + + +F32 LLWindowWin32::getNativeAspectRatio() +{ + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + else if (mNativeAspectRatio > 0.f) + { + // we grabbed this value at startup, based on the user's desktop settings + return mNativeAspectRatio; + } + // RN: this hack presumes that the largest supported resolution is monitor-limited + // and that pixels in that mode are square, therefore defining the native aspect ratio + // of the monitor...this seems to work to a close approximation for most CRTs/LCDs + S32 num_resolutions; + LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); + + return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); +} + +F32 LLWindowWin32::getPixelAspectRatio() +{ + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + getSize(&screen_size); + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } + + return pixel_aspect; } +// Change display resolution. Returns true if successful. +// protected +BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) +{ + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + BOOL success = FALSE; + + // Don't change anything if we don't have to + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == bits && + dev_mode.dmDisplayFrequency == refresh ) + { + // ...display mode identical, do nothing + return TRUE; + } + } -F32 LLWindowWin32::getNativeAspectRatio() -{ - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } - else if (mNativeAspectRatio > 0.f) - { - // we grabbed this value at startup, based on the user's desktop settings - return mNativeAspectRatio; - } - // RN: this hack presumes that the largest supported resolution is monitor-limited - // and that pixels in that mode are square, therefore defining the native aspect ratio - // of the monitor...this seems to work to a close approximation for most CRTs/LCDs - S32 num_resolutions; - LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + dev_mode.dmPelsWidth = width; + dev_mode.dmPelsHeight = height; + dev_mode.dmBitsPerPel = bits; + dev_mode.dmDisplayFrequency = refresh; + dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); -} + // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. + LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); -F32 LLWindowWin32::getPixelAspectRatio() -{ - F32 pixel_aspect = 1.f; - if (getFullscreen()) - { - LLCoordScreen screen_size; - getSize(&screen_size); - pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } + success = (DISP_CHANGE_SUCCESSFUL == cds_result); - return pixel_aspect; -} + if (!success) + { + LL_WARNS("Window") << "setDisplayResolution failed, " + << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; + } -// Change display resolution. Returns true if successful. -// protected -BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) -{ - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - BOOL success = FALSE; - - // Don't change anything if we don't have to - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == bits && - dev_mode.dmDisplayFrequency == refresh ) - { - // ...display mode identical, do nothing - return TRUE; - } - } - - memset(&dev_mode, 0, sizeof(dev_mode)); - dev_mode.dmSize = sizeof(dev_mode); - dev_mode.dmPelsWidth = width; - dev_mode.dmPelsHeight = height; - dev_mode.dmBitsPerPel = bits; - dev_mode.dmDisplayFrequency = refresh; - dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - - // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. - LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); - - success = (DISP_CHANGE_SUCCESSFUL == cds_result); - - if (!success) - { - LL_WARNS("Window") << "setDisplayResolution failed, " - << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; - } - - return success; + return success; } // protected BOOL LLWindowWin32::setFullscreenResolution() { - if (mFullscreen) - { - return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); - } - else - { - return FALSE; - } + if (mFullscreen) + { + return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); + } + else + { + return FALSE; + } } // protected BOOL LLWindowWin32::resetDisplayResolution() { - LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; + LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; - LONG cds_result = ChangeDisplaySettings(NULL, 0); + LONG cds_result = ChangeDisplaySettings(NULL, 0); - BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); + BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); - if (!success) - { - LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; - } + if (!success) + { + LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; + } - LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; + LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; - return success; + return success; } void LLWindowWin32::swapBuffers() @@ -3609,7 +3609,7 @@ void LLWindowWin32::swapBuffers() // LLSplashScreenImp // LLSplashScreenWin32::LLSplashScreenWin32() -: mWindow(NULL) +: mWindow(NULL) { } @@ -3619,14 +3619,14 @@ LLSplashScreenWin32::~LLSplashScreenWin32() void LLSplashScreenWin32::showImpl() { - // This appears to work. ??? - HINSTANCE hinst = GetModuleHandle(NULL); + // This appears to work. ??? + HINSTANCE hinst = GetModuleHandle(NULL); - mWindow = CreateDialog(hinst, - TEXT("SPLASHSCREEN"), - NULL, // no parent - (DLGPROC) LLSplashScreenWin32::windowProc); - ShowWindow(mWindow, SW_SHOW); + mWindow = CreateDialog(hinst, + TEXT("SPLASHSCREEN"), + NULL, // no parent + (DLGPROC) LLSplashScreenWin32::windowProc); + ShowWindow(mWindow, SW_SHOW); // Should set taskbar text without creating a header for the window (caption) SetWindowTextA(mWindow, "Second Life"); @@ -3635,46 +3635,46 @@ void LLSplashScreenWin32::showImpl() void LLSplashScreenWin32::updateImpl(const std::string& mesg) { - if (!mWindow) return; + if (!mWindow) return; - int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); - if( output_str_len>1024 ) - return; + int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); + if( output_str_len>1024 ) + return; - WCHAR w_mesg[1025];//big enought to keep null terminatos + WCHAR w_mesg[1025];//big enought to keep null terminatos - MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); + MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); - //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 - w_mesg[output_str_len] = 0; + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 + w_mesg[output_str_len] = 0; - SendDlgItemMessage(mWindow, - 666, // HACK: text id - WM_SETTEXT, - FALSE, - (LPARAM)w_mesg); + SendDlgItemMessage(mWindow, + 666, // HACK: text id + WM_SETTEXT, + FALSE, + (LPARAM)w_mesg); } void LLSplashScreenWin32::hideImpl() { - if (mWindow) - { + if (mWindow) + { if (!destroy_window_handler(mWindow)) { LL_WARNS("Window") << "Failed to properly close splash screen window!" << LL_ENDL; } - mWindow = NULL; - } + mWindow = NULL; + } } // static LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param) + WPARAM w_param, LPARAM l_param) { - // Just give it to windows - return DefWindowProc(h_wnd, u_msg, w_param, l_param); + // Just give it to windows + return DefWindowProc(h_wnd, u_msg, w_param, l_param); } // @@ -3683,50 +3683,50 @@ LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) { - UINT uType; - - switch(type) - { - case OSMB_OK: - uType = MB_OK; - break; - case OSMB_OKCANCEL: - uType = MB_OKCANCEL; - break; - case OSMB_YESNO: - uType = MB_YESNO; - break; - default: - uType = MB_OK; - break; - } - - int retval_win = MessageBoxW(NULL, // HWND - ll_convert_string_to_wide(text).c_str(), - ll_convert_string_to_wide(caption).c_str(), - uType); - S32 retval; - - switch(retval_win) - { - case IDYES: - retval = OSBTN_YES; - break; - case IDNO: - retval = OSBTN_NO; - break; - case IDOK: - retval = OSBTN_OK; - break; - case IDCANCEL: - retval = OSBTN_CANCEL; - break; - default: - retval = OSBTN_CANCEL; - break; - } - - return retval; + UINT uType; + + switch(type) + { + case OSMB_OK: + uType = MB_OK; + break; + case OSMB_OKCANCEL: + uType = MB_OKCANCEL; + break; + case OSMB_YESNO: + uType = MB_YESNO; + break; + default: + uType = MB_OK; + break; + } + + int retval_win = MessageBoxW(NULL, // HWND + ll_convert_string_to_wide(text).c_str(), + ll_convert_string_to_wide(caption).c_str(), + uType); + S32 retval; + + switch(retval_win) + { + case IDYES: + retval = OSBTN_YES; + break; + case IDNO: + retval = OSBTN_NO; + break; + case IDOK: + retval = OSBTN_OK; + break; + case IDCANCEL: + retval = OSBTN_CANCEL; + break; + default: + retval = OSBTN_CANCEL; + break; + } + + return retval; } void shell_open(const std::string &file, bool async) @@ -3749,27 +3749,27 @@ void shell_open(const std::string &file, bool async) void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) { - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) - { - found = true; - break; - } - } + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) + { + found = true; + break; + } + } - if (!found) - { - LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } + if (!found) + { + LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } - LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; + LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; - // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work - // reliablly on Vista. + // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work + // reliablly on Vista. shell_open(escaped_url, async); } @@ -3780,58 +3780,58 @@ void LLWindowWin32::openFolder(const std::string &path) } /* - Make the raw keyboard data available - used to poke through to LLQtWebKit so - that Qt/Webkit has access to the virtual keycodes etc. that it needs + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs */ LLSD LLWindowWin32::getNativeKeyData() { - LLSD result = LLSD::emptyMap(); + LLSD result = LLSD::emptyMap(); - result["scan_code"] = (S32)mKeyScanCode; - result["virtual_key"] = (S32)mKeyVirtualKey; - result["msg"] = ll_sd_from_U32(mRawMsg); - result["w_param"] = ll_sd_from_U32(mRawWParam); - result["l_param"] = ll_sd_from_U32(mRawLParam); + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["msg"] = ll_sd_from_U32(mRawMsg); + result["w_param"] = ll_sd_from_U32(mRawWParam); + result["l_param"] = ll_sd_from_U32(mRawLParam); - return result; + return result; } BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) { - BOOL retval = FALSE; - - static CHOOSECOLOR cc; - static COLORREF crCustColors[16]; - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = mWindowHandle; - cc.hInstance = NULL; - cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); - //cc.rgbResult = RGB (0x80,0x80,0x80); - cc.lpCustColors = crCustColors; - cc.Flags = CC_RGBINIT | CC_FULLOPEN; - cc.lCustData = 0; - cc.lpfnHook = NULL; - cc.lpTemplateName = NULL; - - // This call is modal, so pause agent - //send_agent_pause(); // this is in newview and we don't want to set up a dependency - { - retval = ChooseColor(&cc); - } - //send_agent_resume(); // this is in newview and we don't want to set up a dependency - - *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; - - *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; - - *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; - - return (retval); + BOOL retval = FALSE; + + static CHOOSECOLOR cc; + static COLORREF crCustColors[16]; + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = mWindowHandle; + cc.hInstance = NULL; + cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); + //cc.rgbResult = RGB (0x80,0x80,0x80); + cc.lpCustColors = crCustColors; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.lCustData = 0; + cc.lpfnHook = NULL; + cc.lpTemplateName = NULL; + + // This call is modal, so pause agent + //send_agent_pause(); // this is in newview and we don't want to set up a dependency + { + retval = ChooseColor(&cc); + } + //send_agent_resume(); // this is in newview and we don't want to set up a dependency + + *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; + + *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; + + *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; + + return (retval); } void *LLWindowWin32::getPlatformWindow() { - return (void*)mWindowHandle; + return (void*)mWindowHandle; } void LLWindowWin32::bringToFront() @@ -3853,40 +3853,40 @@ void LLWindowWin32::focusClient() void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { - if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) - { - return; - } - - if (preeditor != mPreeditor && !b) - { - // This condition may occur with a call to - // setEnabled(BOOL) from LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - if (sLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - sLanguageTextInputAllowed = b; + if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) + { + return; + } + + if (preeditor != mPreeditor && !b) + { + // This condition may occur with a call to + // setEnabled(BOOL) from LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + if (sLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + sLanguageTextInputAllowed = b; if (sLanguageTextInputAllowed) { mWindowThread->post([=]() { - // Allowing: Restore the previous IME status, so that the user has a feeling that the previous - // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps + // Allowing: Restore the previous IME status, so that the user has a feeling that the previous + // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps // using same Input Locale (aka Keyboard Layout). if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) { @@ -3914,7 +3914,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); - // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's + // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's // keyboard hooking, because Some IME reacts only on the former and some other on the latter... LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); LLWinImm::setOpenStatus(himc, FALSE); @@ -3925,194 +3925,194 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) } } -void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, - CANDIDATEFORM *form) +void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, + CANDIDATEFORM *form) { - LLCoordWindow caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + LLCoordWindow caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - memset(form, 0, sizeof(CANDIDATEFORM)); - form->dwStyle = CFS_EXCLUDE; - form->ptCurrentPos.x = caret_coord.mX; - form->ptCurrentPos.y = caret_coord.mY; - form->rcArea.left = top_left.mX; - form->rcArea.top = top_left.mY; - form->rcArea.right = bottom_right.mX; - form->rcArea.bottom = bottom_right.mY; + memset(form, 0, sizeof(CANDIDATEFORM)); + form->dwStyle = CFS_EXCLUDE; + form->ptCurrentPos.x = caret_coord.mX; + form->ptCurrentPos.y = caret_coord.mY; + form->rcArea.left = top_left.mX; + form->rcArea.top = top_left.mY; + form->rcArea.right = bottom_right.mX; + form->rcArea.bottom = bottom_right.mY; } // Put the IME window at the right place (near current text input). Point coordinates should be the top of the current text line. void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) { - if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); + if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); - LLCoordWindow win_pos; - convertCoords( position, &win_pos ); + LLCoordWindow win_pos; + convertCoords( position, &win_pos ); - if ( win_pos.mX >= 0 && win_pos.mY >= 0 && - (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) - { - COMPOSITIONFORM ime_form; - memset( &ime_form, 0, sizeof(ime_form) ); - ime_form.dwStyle = CFS_POINT; - ime_form.ptCurrentPos.x = win_pos.mX; - ime_form.ptCurrentPos.y = win_pos.mY; + if ( win_pos.mX >= 0 && win_pos.mY >= 0 && + (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) + { + COMPOSITIONFORM ime_form; + memset( &ime_form, 0, sizeof(ime_form) ); + ime_form.dwStyle = CFS_POINT; + ime_form.ptCurrentPos.x = win_pos.mX; + ime_form.ptCurrentPos.y = win_pos.mY; - LLWinImm::setCompositionWindow( himc, &ime_form ); + LLWinImm::setCompositionWindow( himc, &ime_form ); - sWinIMEWindowPosition = win_pos; - } + sWinIMEWindowPosition = win_pos; + } - LLWinImm::releaseContext(mWindowHandle, himc); - } + LLWinImm::releaseContext(mWindowHandle, himc); + } } void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, - IMECHARPOSITION *char_position) + IMECHARPOSITION *char_position) { - LLCoordScreen caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + LLCoordScreen caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - char_position->pt.x = caret_coord.mX; - char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... - char_position->cLineHeight = bottom_right.mY - top_left.mY; - char_position->rcDocument.left = top_left.mX; - char_position->rcDocument.top = top_left.mY; - char_position->rcDocument.right = bottom_right.mX; - char_position->rcDocument.bottom = bottom_right.mY; + char_position->pt.x = caret_coord.mX; + char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... + char_position->cLineHeight = bottom_right.mY - top_left.mY; + char_position->rcDocument.left = top_left.mX; + char_position->rcDocument.top = top_left.mY; + char_position->rcDocument.right = bottom_right.mX; + char_position->rcDocument.bottom = bottom_right.mY; } void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) { - // Our font is a list of FreeType recognized font files that may - // not have a corresponding ones in Windows' fonts. Hence, we - // can't simply tell Windows which font we are using. We will - // notify a _standard_ font for a current input locale instead. - // We use a hard-coded knowledge about the Windows' standard - // configuration to do so... - - memset(logfont, 0, sizeof(LOGFONT)); - - const WORD lang_id = LOWORD(GetKeyboardLayout(0)); - switch (PRIMARYLANGID(lang_id)) - { - case LANG_CHINESE: - // We need to identify one of two Chinese fonts. - switch (SUBLANGID(lang_id)) - { - case SUBLANG_CHINESE_SIMPLIFIED: - case SUBLANG_CHINESE_SINGAPORE: - logfont->lfCharSet = GB2312_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("SimHei")); - break; - case SUBLANG_CHINESE_TRADITIONAL: - case SUBLANG_CHINESE_HONGKONG: - case SUBLANG_CHINESE_MACAU: - default: - logfont->lfCharSet = CHINESEBIG5_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); - break; - } - break; - case LANG_JAPANESE: - logfont->lfCharSet = SHIFTJIS_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); - break; - case LANG_KOREAN: - logfont->lfCharSet = HANGUL_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Gulim")); - break; - default: - logfont->lfCharSet = ANSI_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); - break; - } - - logfont->lfHeight = mPreeditor->getPreeditFontSize(); - logfont->lfWeight = FW_NORMAL; -} + // Our font is a list of FreeType recognized font files that may + // not have a corresponding ones in Windows' fonts. Hence, we + // can't simply tell Windows which font we are using. We will + // notify a _standard_ font for a current input locale instead. + // We use a hard-coded knowledge about the Windows' standard + // configuration to do so... -U32 LLWindowWin32::fillReconvertString(const LLWString &text, - S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) -{ - const llutf16string text_utf16 = wstring_to_utf16str(text); - const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); - if (reconvert_string && reconvert_string->dwSize >= required_size) - { - const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); - const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); + memset(logfont, 0, sizeof(LOGFONT)); + + const WORD lang_id = LOWORD(GetKeyboardLayout(0)); + switch (PRIMARYLANGID(lang_id)) + { + case LANG_CHINESE: + // We need to identify one of two Chinese fonts. + switch (SUBLANGID(lang_id)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + case SUBLANG_CHINESE_SINGAPORE: + logfont->lfCharSet = GB2312_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("SimHei")); + break; + case SUBLANG_CHINESE_TRADITIONAL: + case SUBLANG_CHINESE_HONGKONG: + case SUBLANG_CHINESE_MACAU: + default: + logfont->lfCharSet = CHINESEBIG5_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); + break; + } + break; + case LANG_JAPANESE: + logfont->lfCharSet = SHIFTJIS_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); + break; + case LANG_KOREAN: + logfont->lfCharSet = HANGUL_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Gulim")); + break; + default: + logfont->lfCharSet = ANSI_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); + break; + } - reconvert_string->dwVersion = 0; - reconvert_string->dwStrLen = text_utf16.length(); - reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); - reconvert_string->dwCompStrLen = focus_utf16_length; - reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); - reconvert_string->dwTargetStrLen = 0; - reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); + logfont->lfHeight = mPreeditor->getPreeditFontSize(); + logfont->lfWeight = FW_NORMAL; +} - const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); - memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); - } - return required_size; +U32 LLWindowWin32::fillReconvertString(const LLWString &text, + S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) +{ + const llutf16string text_utf16 = wstring_to_utf16str(text); + const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); + if (reconvert_string && reconvert_string->dwSize >= required_size) + { + const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); + const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); + + reconvert_string->dwVersion = 0; + reconvert_string->dwStrLen = text_utf16.length(); + reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); + reconvert_string->dwCompStrLen = focus_utf16_length; + reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); + reconvert_string->dwTargetStrLen = 0; + reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); + + const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); + memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); + } + return required_size; } void LLWindowWin32::updateLanguageTextInputArea() { - if (!mPreeditor || !LLWinImm::isAvailable()) - { - return; - } - - LLCoordGL caret_coord; - LLRect preedit_bounds; - if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) - { - mLanguageTextInputPointGL = caret_coord; - mLanguageTextInputAreaGL = preedit_bounds; - - CANDIDATEFORM candidate_form; - fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); - - HIMC himc = LLWinImm::getContext(mWindowHandle); - // Win32 document says there may be up to 4 candidate windows. - // This magic number 4 appears only in the document, and - // there are no constant/macro for the value... - for (int i = 3; i >= 0; --i) - { - candidate_form.dwIndex = i; - LLWinImm::setCandidateWindow(himc, &candidate_form); - } - LLWinImm::releaseContext(mWindowHandle, himc); - } + if (!mPreeditor || !LLWinImm::isAvailable()) + { + return; + } + + LLCoordGL caret_coord; + LLRect preedit_bounds; + if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) + { + mLanguageTextInputPointGL = caret_coord; + mLanguageTextInputAreaGL = preedit_bounds; + + CANDIDATEFORM candidate_form; + fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); + + HIMC himc = LLWinImm::getContext(mWindowHandle); + // Win32 document says there may be up to 4 candidate windows. + // This magic number 4 appears only in the document, and + // there are no constant/macro for the value... + for (int i = 3; i >= 0; --i) + { + candidate_form.dwIndex = i; + LLWinImm::setCandidateWindow(himc, &candidate_form); + } + LLWinImm::releaseContext(mWindowHandle, himc); + } } void LLWindowWin32::interruptLanguageTextInput() { ASSERT_MAIN_THREAD(); - if (mPreeditor && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - } + if (mPreeditor && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + } } void LLWindowWin32::handleStartCompositionMessage() { - // Let IME know the font to use in feedback UI. - LOGFONT logfont; - fillCompositionLogfont(&logfont); - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setCompositionFont(himc, &logfont); - LLWinImm::releaseContext(mWindowHandle, himc); + // Let IME know the font to use in feedback UI. + LOGFONT logfont; + fillCompositionLogfont(&logfont); + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::setCompositionFont(himc, &logfont); + LLWinImm::releaseContext(mWindowHandle, himc); } // Handle WM_IME_COMPOSITION message. @@ -4123,156 +4123,156 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) { return; } - BOOL needs_update = FALSE; - LLWString result_string; - LLWString preedit_string; - S32 preedit_string_utf16_length = 0; - LLPreeditor::segment_lengths_t preedit_segment_lengths; - LLPreeditor::standouts_t preedit_standouts; - - // Step I: Receive details of preedits from IME. - - HIMC himc = LLWinImm::getContext(mWindowHandle); - - if (indexes & GCS_RESULTSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); - if (size > 0) - { - result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = TRUE; - } - } - - if (indexes & GCS_COMPSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); - if (size > 0) - { - preedit_string_utf16_length = size / sizeof(WCHAR); - preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = TRUE; - } - } - - if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); - if (size > 0) - { - const LPDWORD data = new DWORD[size / sizeof(DWORD)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); - if (size >= sizeof(DWORD) * 2 - && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) - { - preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); - preedit_segment_lengths[i] = length; - offset += length; - } - } - delete[] data; - } - } - - if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); - if (size > 0) - { - const LPBYTE data = new BYTE[size / sizeof(BYTE)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); - if (size == preedit_string_utf16_length) - { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) - { - preedit_standouts[i] = TRUE; - } - offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); - } - } - delete[] data; - } - } - - S32 caret_position = preedit_string.length(); - if (indexes & GCS_CURSORPOS) - { - const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); - if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) - { - caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); - } - } - - if (indexes == 0) - { - // I'm not sure this condition really happens, but - // Windows SDK document says it is an indication - // of "reset everything." - needs_update = TRUE; - } - - LLWinImm::releaseContext(mWindowHandle, himc); - - // Step II: Update the active preeditor. - - if (needs_update) - { + BOOL needs_update = FALSE; + LLWString result_string; + LLWString preedit_string; + S32 preedit_string_utf16_length = 0; + LLPreeditor::segment_lengths_t preedit_segment_lengths; + LLPreeditor::standouts_t preedit_standouts; + + // Step I: Receive details of preedits from IME. + + HIMC himc = LLWinImm::getContext(mWindowHandle); + + if (indexes & GCS_RESULTSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); + if (size > 0) + { + result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = TRUE; + } + } + + if (indexes & GCS_COMPSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); + if (size > 0) + { + preedit_string_utf16_length = size / sizeof(WCHAR); + preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = TRUE; + } + } + + if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); + if (size > 0) + { + const LPDWORD data = new DWORD[size / sizeof(DWORD)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); + if (size >= sizeof(DWORD) * 2 + && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) + { + preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); + preedit_segment_lengths[i] = length; + offset += length; + } + } + delete[] data; + } + } + + if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); + if (size > 0) + { + const LPBYTE data = new BYTE[size / sizeof(BYTE)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); + if (size == preedit_string_utf16_length) + { + preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) + { + preedit_standouts[i] = TRUE; + } + offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); + } + } + delete[] data; + } + } + + S32 caret_position = preedit_string.length(); + if (indexes & GCS_CURSORPOS) + { + const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); + if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) + { + caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); + } + } + + if (indexes == 0) + { + // I'm not sure this condition really happens, but + // Windows SDK document says it is an indication + // of "reset everything." + needs_update = TRUE; + } + + LLWinImm::releaseContext(mWindowHandle, himc); + + // Step II: Update the active preeditor. + + if (needs_update) + { if (preedit_string.length() != 0 || result_string.length() != 0) { mPreeditor->resetPreedit(); } - if (result_string.length() > 0) - { - for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) - { - mPreeditor->handleUnicodeCharHere(*i); - } - } - - if (preedit_string.length() == 0) - { - preedit_segment_lengths.clear(); - preedit_standouts.clear(); - } - else - { - if (preedit_segment_lengths.size() == 0) - { - preedit_segment_lengths.assign(1, preedit_string.length()); - } - if (preedit_standouts.size() == 0) - { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); - } - } - mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); - - // Some IME doesn't query char position after WM_IME_COMPOSITION, - // so we need to update them actively. - updateLanguageTextInputArea(); - } + if (result_string.length() > 0) + { + for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) + { + mPreeditor->handleUnicodeCharHere(*i); + } + } + + if (preedit_string.length() == 0) + { + preedit_segment_lengths.clear(); + preedit_standouts.clear(); + } + else + { + if (preedit_segment_lengths.size() == 0) + { + preedit_segment_lengths.assign(1, preedit_string.length()); + } + if (preedit_standouts.size() == 0) + { + preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + } + } + mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); + + // Some IME doesn't query char position after WM_IME_COMPOSITION, + // so we need to update them actively. + updateLanguageTextInputArea(); + } } // Given a text and a focus range, find_context finds and returns a @@ -4282,24 +4282,24 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) { - static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. + static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. - const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); - S32 end = focus + focus_length; - while (end < e && '\n' != wtext[end]) - { - end++; - } + const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); + S32 end = focus + focus_length; + while (end < e && '\n' != wtext[end]) + { + end++; + } - const S32 s = llmax(0, focus - CONTEXT_EXCESS); - S32 start = focus; - while (start > s && '\n' != wtext[start - 1]) - { - --start; - } + const S32 s = llmax(0, focus - CONTEXT_EXCESS); + S32 start = focus; + while (start > s && '\n' != wtext[start - 1]) + { + --start; + } - *offset = start; - return wtext.substr(start, end - start); + *offset = start; + return wtext.substr(start, end - start); } // final stage of handling drop requests - both from WM_DROPFILES message @@ -4307,7 +4307,7 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ) { ASSERT_MAIN_THREAD(); - return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); + return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); } // Handle WM_IME_REQUEST message. @@ -4317,153 +4317,153 @@ LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( cons BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result) { - if ( mPreeditor ) - { - switch (request) - { - case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx - { - LLCoordGL caret_coord; - LLRect preedit_bounds; - mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); - - CANDIDATEFORM *const form = (CANDIDATEFORM *)param; - DWORD const dwIndex = form->dwIndex; - fillCandidateForm(caret_coord, preedit_bounds, form); - form->dwIndex = dwIndex; - - *result = 1; - return TRUE; - } - case IMR_QUERYCHARPOSITION: - { - IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; - - // char_position->dwCharPos counts in number of - // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the - // number to getPreeditLocation. - - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - LLCoordGL caret_coord; - LLRect preedit_bounds, text_control; - const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); - - if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) - { - LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; - return FALSE; - } - - fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); - - *result = 1; - return TRUE; - } - case IMR_COMPOSITIONFONT: - { - fillCompositionLogfont((LOGFONT *)param); - - *result = 1; - return TRUE; - } - case IMR_RECONVERTSTRING: - { - mPreeditor->resetPreedit(); - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 select, select_length; - mPreeditor->getSelectionRange(&select, &select_length); - - S32 context_offset; - const LLWString context = find_context(wtext, select, select_length, &context_offset); - - RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; - const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); - if (reconvert_string) - { - if (select_length == 0) - { - // Let the IME to decide the reconversion range, and - // adjust the reconvert_string structure accordingly. - HIMC himc = LLWinImm::getContext(mWindowHandle); - const BOOL adjusted = LLWinImm::setCompositionString(himc, - SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - if (adjusted) - { - const llutf16string & text_utf16 = wstring_to_utf16str(context); - const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); - const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; - select = utf16str_wstring_length(text_utf16, new_preedit_start); - select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; - select += context_offset; - } - } - mPreeditor->markAsPreedit(select, select_length); - } - - *result = size; - return TRUE; - } - case IMR_CONFIRMRECONVERTSTRING: - { - *result = FALSE; - return TRUE; - } - case IMR_DOCUMENTFEED: - { - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - - S32 context_offset; - LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); - preedit -= context_offset; - preedit_length = llmin(preedit_length, (S32)context.length() - preedit); - if (preedit_length > 0 && preedit >= 0) - { - // IMR_DOCUMENTFEED may be called when we have an active preedit. - // We should pass the context string *excluding* the preedit string. - // Otherwise, some IME are confused. - context.erase(preedit, preedit_length); - } - - RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; - *result = fillReconvertString(context, preedit, 0, reconvert_string); - return TRUE; - } - default: - return FALSE; - } - } - - return FALSE; + if ( mPreeditor ) + { + switch (request) + { + case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx + { + LLCoordGL caret_coord; + LLRect preedit_bounds; + mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); + + CANDIDATEFORM *const form = (CANDIDATEFORM *)param; + DWORD const dwIndex = form->dwIndex; + fillCandidateForm(caret_coord, preedit_bounds, form); + form->dwIndex = dwIndex; + + *result = 1; + return TRUE; + } + case IMR_QUERYCHARPOSITION: + { + IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; + + // char_position->dwCharPos counts in number of + // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the + // number to getPreeditLocation. + + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + LLCoordGL caret_coord; + LLRect preedit_bounds, text_control; + const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); + + if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) + { + LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; + return FALSE; + } + + fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); + + *result = 1; + return TRUE; + } + case IMR_COMPOSITIONFONT: + { + fillCompositionLogfont((LOGFONT *)param); + + *result = 1; + return TRUE; + } + case IMR_RECONVERTSTRING: + { + mPreeditor->resetPreedit(); + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 select, select_length; + mPreeditor->getSelectionRange(&select, &select_length); + + S32 context_offset; + const LLWString context = find_context(wtext, select, select_length, &context_offset); + + RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; + const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); + if (reconvert_string) + { + if (select_length == 0) + { + // Let the IME to decide the reconversion range, and + // adjust the reconvert_string structure accordingly. + HIMC himc = LLWinImm::getContext(mWindowHandle); + const BOOL adjusted = LLWinImm::setCompositionString(himc, + SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + if (adjusted) + { + const llutf16string & text_utf16 = wstring_to_utf16str(context); + const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); + const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; + select = utf16str_wstring_length(text_utf16, new_preedit_start); + select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; + select += context_offset; + } + } + mPreeditor->markAsPreedit(select, select_length); + } + + *result = size; + return TRUE; + } + case IMR_CONFIRMRECONVERTSTRING: + { + *result = FALSE; + return TRUE; + } + case IMR_DOCUMENTFEED: + { + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + + S32 context_offset; + LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); + preedit -= context_offset; + preedit_length = llmin(preedit_length, (S32)context.length() - preedit); + if (preedit_length > 0 && preedit >= 0) + { + // IMR_DOCUMENTFEED may be called when we have an active preedit. + // We should pass the context string *excluding* the preedit string. + // Otherwise, some IME are confused. + context.erase(preedit, preedit_length); + } + + RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; + *result = fillReconvertString(context, preedit, 0, reconvert_string); + return TRUE; + } + default: + return FALSE; + } + } + + return FALSE; } //static void LLWindowWin32::setDPIAwareness() { - HMODULE hShcore = LoadLibrary(L"shcore.dll"); - if (hShcore != NULL) - { - SetProcessDpiAwarenessType pSPDA; - pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); - if (pSPDA) - { - - HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); - if (hr != S_OK) - { - LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; - } - } - FreeLibrary(hShcore); - } - else - { - LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; - } + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + if (hShcore != NULL) + { + SetProcessDpiAwarenessType pSPDA; + pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); + if (pSPDA) + { + + HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); + if (hr != S_OK) + { + LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } } void* LLWindowWin32::getDirectInput8() @@ -4490,76 +4490,76 @@ bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_c F32 LLWindowWin32::getSystemUISize() { - F32 scale_value = 1.f; - HWND hWnd = (HWND)getPlatformWindow(); - HDC hdc = GetDC(hWnd); - HMONITOR hMonitor; - HANDLE hProcess = GetCurrentProcess(); - PROCESS_DPI_AWARENESS dpi_awareness; - - HMODULE hShcore = LoadLibrary(L"shcore.dll"); - - if (hShcore != NULL) - { - GetProcessDpiAwarenessType pGPDA; - pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); - GetDpiForMonitorType pGDFM; - pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); - if (pGPDA != NULL && pGDFM != NULL) - { - pGPDA(hProcess, &dpi_awareness); - if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) - { - POINT pt; - UINT dpix = 0, dpiy = 0; - HRESULT hr = E_FAIL; - RECT rect; - - GetWindowRect(hWnd, &rect); - // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor - pt.x = (rect.left + rect.right) / 2; - pt.y = (rect.top + rect.bottom) / 2; - hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); - hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); - if (hr == S_OK) - { - scale_value = F32(dpix) / F32(USER_DEFAULT_SCREEN_DPI); - } - else - { - LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; - scale_value = 1.0f; - } - } - else - { - LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; - scale_value = 1.0f; - } - } - FreeLibrary(hShcore); - } - else - { - LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; - scale_value = F32(GetDeviceCaps(hdc, LOGPIXELSX)) / F32(USER_DEFAULT_SCREEN_DPI); - } - - ReleaseDC(hWnd, hdc); - return scale_value; + F32 scale_value = 1.f; + HWND hWnd = (HWND)getPlatformWindow(); + HDC hdc = GetDC(hWnd); + HMONITOR hMonitor; + HANDLE hProcess = GetCurrentProcess(); + PROCESS_DPI_AWARENESS dpi_awareness; + + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + + if (hShcore != NULL) + { + GetProcessDpiAwarenessType pGPDA; + pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); + GetDpiForMonitorType pGDFM; + pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); + if (pGPDA != NULL && pGDFM != NULL) + { + pGPDA(hProcess, &dpi_awareness); + if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) + { + POINT pt; + UINT dpix = 0, dpiy = 0; + HRESULT hr = E_FAIL; + RECT rect; + + GetWindowRect(hWnd, &rect); + // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor + pt.x = (rect.left + rect.right) / 2; + pt.y = (rect.top + rect.bottom) / 2; + hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); + if (hr == S_OK) + { + scale_value = F32(dpix) / F32(USER_DEFAULT_SCREEN_DPI); + } + else + { + LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + else + { + LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; + scale_value = F32(GetDeviceCaps(hdc, LOGPIXELSX)) / F32(USER_DEFAULT_SCREEN_DPI); + } + + ReleaseDC(hWnd, hdc); + return scale_value; } //static std::vector LLWindowWin32::getDisplaysResolutionList() -{ - return sMonitorInfo.getResolutionsList(); +{ + return sMonitorInfo.getResolutionsList(); } //static std::vector LLWindowWin32::getDynamicFallbackFontList() { - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector(); + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector(); } U32 LLWindowWin32::getAvailableVRAMMegabytes() @@ -4743,7 +4743,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) { mD3D = Direct3DCreate9(D3D_SDK_VERSION); - + D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); @@ -4751,7 +4751,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); - + if (FAILED(res)) { LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL; @@ -4808,7 +4808,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() U32 afr_mb = info.AvailableForReservation / 1024 / 1024; // correct for systems that misreport budget if (budget_mb == 0) - { + { // fall back to available for reservation clamped between 512MB and 2GB budget_mb = llclamp(afr_mb, (U32) 512, (U32) 2048); } @@ -4829,7 +4829,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() } U32 target_mb = budget_mb; - if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free + if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free { target_mb -= 2048; } @@ -4841,7 +4841,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0; #if 0 - + F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb; LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024 << "\nBudget: " << info.Budget / 1024 / 1024 @@ -4915,7 +4915,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() //process any pending functions getQueue().runPending(); } - + // update available vram once every 3 seconds static LLFrameTimer vramTimer; if (vramTimer.getElapsedTimeF32() > 3.f) @@ -5071,11 +5071,11 @@ void LLWindowWin32::updateWindowRect() //called from window thread RECT rect; RECT client_rect; - + if (GetWindowRect(mWindowHandle, &rect) && GetClientRect(mWindowHandle, &client_rect)) { - post([=] + post([=] { mRect = rect; mClientRect = client_rect; diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 320c1c8b88..6801dfe1be 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -1,25 +1,25 @@ -/** +/** * @file llwindowwin32.h * @brief Windows implementation of LLWindow class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,92 +45,92 @@ typedef void (*LLW32MsgCallback)(const MSG &msg); class LLWindowWin32 : public LLWindow { public: - /*virtual*/ void show(); - /*virtual*/ void hide(); - /*virtual*/ void close(); - /*virtual*/ BOOL getVisible(); - /*virtual*/ BOOL getMinimized(); - /*virtual*/ BOOL getMaximized(); - /*virtual*/ BOOL maximize(); - /*virtual*/ void minimize(); - /*virtual*/ void restore(); - /*virtual*/ BOOL getFullscreen(); - /*virtual*/ BOOL getPosition(LLCoordScreen *position); - /*virtual*/ BOOL getSize(LLCoordScreen *size); - /*virtual*/ BOOL getSize(LLCoordWindow *size); - /*virtual*/ BOOL setPosition(LLCoordScreen position); - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); - /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ void show(); + /*virtual*/ void hide(); + /*virtual*/ void close(); + /*virtual*/ BOOL getVisible(); + /*virtual*/ BOOL getMinimized(); + /*virtual*/ BOOL getMaximized(); + /*virtual*/ BOOL maximize(); + /*virtual*/ void minimize(); + /*virtual*/ void restore(); + /*virtual*/ BOOL getFullscreen(); + /*virtual*/ BOOL getPosition(LLCoordScreen *position); + /*virtual*/ BOOL getSize(LLCoordScreen *size); + /*virtual*/ BOOL getSize(LLCoordWindow *size); + /*virtual*/ BOOL setPosition(LLCoordScreen position); + /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); + /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL); /*virtual*/ void setTitle(const std::string title); void* createSharedContext() override; void makeContextCurrent(void* context) override; void destroySharedContext(void* context) override; /*virtual*/ void toggleVSync(bool enable_vsync); - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); + /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); + /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta); - /*virtual*/ void showCursor(); - /*virtual*/ void hideCursor(); - /*virtual*/ void showCursorFromMouseMove(); - /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ BOOL isCursorHidden(); - /*virtual*/ void updateCursor(); - /*virtual*/ ECursorType getCursor() const; - /*virtual*/ void captureMouse(); - /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( BOOL b ); - /*virtual*/ BOOL isClipboardTextAvailable(); - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); - /*virtual*/ BOOL copyTextToClipboard(const LLWString &src); - /*virtual*/ void flashIcon(F32 seconds); - /*virtual*/ F32 getGamma(); - /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma - /*virtual*/ void setFSAASamples(const U32 fsaa_samples); - /*virtual*/ U32 getFSAASamples(); - /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) - /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput(); - /*virtual*/ void delayInputProcessing(); - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; - - // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + /*virtual*/ void showCursor(); + /*virtual*/ void hideCursor(); + /*virtual*/ void showCursorFromMouseMove(); + /*virtual*/ void hideCursorUntilMouseMove(); + /*virtual*/ BOOL isCursorHidden(); + /*virtual*/ void updateCursor(); + /*virtual*/ ECursorType getCursor() const; + /*virtual*/ void captureMouse(); + /*virtual*/ void releaseMouse(); + /*virtual*/ void setMouseClipping( BOOL b ); + /*virtual*/ BOOL isClipboardTextAvailable(); + /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); + /*virtual*/ BOOL copyTextToClipboard(const LLWString &src); + /*virtual*/ void flashIcon(F32 seconds); + /*virtual*/ F32 getGamma(); + /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma + /*virtual*/ void setFSAASamples(const U32 fsaa_samples); + /*virtual*/ U32 getFSAASamples(); + /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } + /*virtual*/ void gatherInput(); + /*virtual*/ void delayInputProcessing(); + /*virtual*/ void swapBuffers(); + /*virtual*/ void restoreGLContext() {}; + + // handy coordinate space conversion routines + /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); + /*virtual*/ F32 getNativeAspectRatio(); + /*virtual*/ F32 getPixelAspectRatio(); + /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } U32 getAvailableVRAMMegabytes() override; - - /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); - /*virtual*/ void focusClient(); + /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); + + /*virtual*/ void *getPlatformWindow(); + /*virtual*/ void bringToFront(); + /*virtual*/ void focusClient(); - /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); - /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); - /*virtual*/ void updateLanguageTextInputArea(); - /*virtual*/ void interruptLanguageTextInput(); - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); + /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); + /*virtual*/ void updateLanguageTextInputArea(); + /*virtual*/ void interruptLanguageTextInput(); + /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); void openFolder(const std::string &path) override; - /*virtual*/ F32 getSystemUISize(); + /*virtual*/ F32 getSystemUISize(); - LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); + LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); - static std::vector getDisplaysResolutionList(); - static std::vector getDynamicFallbackFontList(); - static void setDPIAwareness(); + static std::vector getDisplaysResolutionList(); + static std::vector getDynamicFallbackFontList(); + static void setDPIAwareness(); /*virtual*/ void* getDirectInput8(); /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata); @@ -138,67 +138,67 @@ public: U32 getRawWParam() { return mRawWParam; } protected: - LLWindowWin32(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); - ~LLWindowWin32(); - - void initCursors(); - void initInputDevices(); - HCURSOR loadColorCursor(LPCTSTR name); - BOOL isValid(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - virtual LLSD getNativeKeyData(); - - // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - - // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); - - // Restore the display resolution to its value before we ran the app. - BOOL resetDisplayResolution(); - - BOOL shouldPostQuit() { return mPostQuit; } - - void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); - void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); - void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); - void fillCompositionLogfont(LOGFONT *logfont); - U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); - void handleStartCompositionMessage(); - void handleCompositionMessage(U32 indexes); - BOOL handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); + LLWindowWin32(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, + BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); + ~LLWindowWin32(); + + void initCursors(); + void initInputDevices(); + HCURSOR loadColorCursor(LPCTSTR name); + BOOL isValid(); + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + virtual LLSD getNativeKeyData(); + + // Changes display resolution. Returns true if successful + BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + + // Go back to last fullscreen display resolution. + BOOL setFullscreenResolution(); + + // Restore the display resolution to its value before we ran the app. + BOOL resetDisplayResolution(); + + BOOL shouldPostQuit() { return mPostQuit; } + + void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); + void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); + void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); + void fillCompositionLogfont(LOGFONT *logfont); + U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); + void handleStartCompositionMessage(); + void handleCompositionMessage(U32 indexes); + BOOL handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); protected: - // - // Platform specific methods - // + // + // Platform specific methods + // - BOOL getClientRectInScreenSpace(RECT* rectp); - void updateJoystick( ); + BOOL getClientRectInScreenSpace(RECT* rectp); + void updateJoystick( ); - static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); - static BOOL CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); + static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); + static BOOL CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); - // - // Platform specific variables - // - WCHAR *mWindowTitle; - WCHAR *mWindowClassName; + // + // Platform specific variables + // + WCHAR *mWindowTitle; + WCHAR *mWindowClassName; - HWND mWindowHandle = 0; // window handle - HGLRC mhRC = 0; // OpenGL rendering context - HDC mhDC = 0; // Windows Device context handle - HINSTANCE mhInstance; // handle to application instance - RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - WPARAM mLastSizeWParam; - F32 mOverrideAspectRatio; - F32 mNativeAspectRatio; + HWND mWindowHandle = 0; // window handle + HGLRC mhRC = 0; // OpenGL rendering context + HDC mhDC = 0; // Windows Device context handle + HINSTANCE mhInstance; // handle to application instance + RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + WPARAM mLastSizeWParam; + F32 mOverrideAspectRatio; + F32 mNativeAspectRatio; - HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors + HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors LLCoordWindow mCursorPosition; // mouse cursor position, should only be mutated on main thread LLMutex mRawMouseMutex; RAWINPUTDEVICE mRawMouse; @@ -208,86 +208,86 @@ protected: MASK mMouseMask; - static BOOL sIsClassRegistered; // has the window class been registered? + static BOOL sIsClassRegistered; // has the window class been registered? - F32 mCurrentGamma; - U32 mFSAASamples; + F32 mCurrentGamma; + U32 mFSAASamples; U32 mMaxCores; // for debugging only -- maximum number of CPU cores to use, or 0 for no limit F32 mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6) - WORD mPrevGammaRamp[3][256]; - WORD mCurrentGammaRamp[3][256]; - BOOL mCustomGammaSet; - - LPWSTR mIconResource; - BOOL mInputProcessingPaused; - - // The following variables are for Language Text Input control. - // They are all static, since one context is shared by all LLWindowWin32 - // instances. - static BOOL sLanguageTextInputAllowed; - static BOOL sWinIMEOpened; - static HKL sWinInputLocale; - static DWORD sWinIMEConversionMode; - static DWORD sWinIMESentenceMode; - static LLCoordWindow sWinIMEWindowPosition; - LLCoordGL mLanguageTextInputPointGL; - LLRect mLanguageTextInputAreaGL; - - LLPreeditor *mPreeditor; - - LLDragDropWin32* mDragDrop; - - U32 mKeyCharCode; - U32 mKeyScanCode; - U32 mKeyVirtualKey; - U32 mRawMsg; - U32 mRawWParam; - U32 mRawLParam; - - BOOL mMouseVanish; + WORD mPrevGammaRamp[3][256]; + WORD mCurrentGammaRamp[3][256]; + BOOL mCustomGammaSet; + + LPWSTR mIconResource; + BOOL mInputProcessingPaused; + + // The following variables are for Language Text Input control. + // They are all static, since one context is shared by all LLWindowWin32 + // instances. + static BOOL sLanguageTextInputAllowed; + static BOOL sWinIMEOpened; + static HKL sWinInputLocale; + static DWORD sWinIMEConversionMode; + static DWORD sWinIMESentenceMode; + static LLCoordWindow sWinIMEWindowPosition; + LLCoordGL mLanguageTextInputPointGL; + LLRect mLanguageTextInputAreaGL; + + LLPreeditor *mPreeditor; + + LLDragDropWin32* mDragDrop; + + U32 mKeyCharCode; + U32 mKeyScanCode; + U32 mKeyVirtualKey; + U32 mRawMsg; + U32 mRawWParam; + U32 mRawLParam; + + BOOL mMouseVanish; // Cached values of GetWindowRect and GetClientRect to be used by app thread void updateWindowRect(); - RECT mRect; + RECT mRect; RECT mClientRect; - struct LLWindowWin32Thread; - LLWindowWin32Thread* mWindowThread = nullptr; - LLThreadSafeQueue> mFunctionQueue; - LLThreadSafeQueue> mMouseQueue; - void post(const std::function& func); - void postMouseButtonEvent(const std::function& func); - void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); - void kickWindowThread(HWND windowHandle=0); + struct LLWindowWin32Thread; + LLWindowWin32Thread* mWindowThread = nullptr; + LLThreadSafeQueue> mFunctionQueue; + LLThreadSafeQueue> mMouseQueue; + void post(const std::function& func); + void postMouseButtonEvent(const std::function& func); + void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); + void kickWindowThread(HWND windowHandle=0); - friend class LLWindowManager; + friend class LLWindowManager; }; class LLSplashScreenWin32 : public LLSplashScreen { public: - LLSplashScreenWin32(); - virtual ~LLSplashScreenWin32(); + LLSplashScreenWin32(); + virtual ~LLSplashScreenWin32(); - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); + /*virtual*/ void showImpl(); + /*virtual*/ void updateImpl(const std::string& mesg); + /*virtual*/ void hideImpl(); #if LL_WINDOWS - static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param); + static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, + WPARAM w_param, LPARAM l_param); #endif private: #if LL_WINDOWS - HWND mWindow; + HWND mWindow; #endif }; extern LLW32MsgCallback gAsyncMsgCallback; extern LPWSTR gIconResource; -static void handleMessage( const MSG& msg ); +static void handleMessage( const MSG& msg ); S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index a2178ed77d..1194e0c3bc 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcontrol.cpp * @brief Holds global state for viewer. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -109,60 +109,60 @@ std::string SETTINGS_PROFILE = "settings_profile.log"; bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) { - bool result = false; - switch (mType) - { - case TYPE_U32: - case TYPE_S32: - result = a.asInteger() == b.asInteger(); - break; - case TYPE_BOOLEAN: - result = a.asBoolean() == b.asBoolean(); - break; - case TYPE_F32: - result = a.asReal() == b.asReal(); - break; - case TYPE_VEC3: - case TYPE_VEC3D: - result = LLVector3d(a) == LLVector3d(b); - break; - case TYPE_QUAT: - result = LLQuaternion(a) == LLQuaternion(b); - break; - case TYPE_RECT: - result = LLRect(a) == LLRect(b); - break; - case TYPE_COL4: - result = LLColor4(a) == LLColor4(b); - break; - case TYPE_COL3: - result = LLColor3(a) == LLColor3(b); - break; - case TYPE_STRING: - result = a.asString() == b.asString(); - break; - default: - break; - } - - return result; + bool result = false; + switch (mType) + { + case TYPE_U32: + case TYPE_S32: + result = a.asInteger() == b.asInteger(); + break; + case TYPE_BOOLEAN: + result = a.asBoolean() == b.asBoolean(); + break; + case TYPE_F32: + result = a.asReal() == b.asReal(); + break; + case TYPE_VEC3: + case TYPE_VEC3D: + result = LLVector3d(a) == LLVector3d(b); + break; + case TYPE_QUAT: + result = LLQuaternion(a) == LLQuaternion(b); + break; + case TYPE_RECT: + result = LLRect(a) == LLRect(b); + break; + case TYPE_COL4: + result = LLColor4(a) == LLColor4(b); + break; + case TYPE_COL3: + result = LLColor3(a) == LLColor3(b); + break; + case TYPE_STRING: + result = a.asString() == b.asString(); + break; + default: + break; + } + + return result; } LLControlVariable::LLControlVariable(const std::string& name, eControlType type, - LLSD initial, const std::string& comment, - ePersist persist, bool hidefromsettingseditor) - : mName(name), - mComment(comment), - mType(type), - mPersist(persist), - mHideFromSettingsEditor(hidefromsettingseditor) -{ - if ((persist != PERSIST_NO) && mComment.empty()) - { - LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; - } - //Push back versus setValue'ing here, since we don't want to call a signal yet - mValues.push_back(initial); + LLSD initial, const std::string& comment, + ePersist persist, bool hidefromsettingseditor) + : mName(name), + mComment(comment), + mType(type), + mPersist(persist), + mHideFromSettingsEditor(hidefromsettingseditor) +{ + if ((persist != PERSIST_NO) && mComment.empty()) + { + LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; + } + //Push back versus setValue'ing here, since we don't want to call a signal yet + mValues.push_back(initial); } @@ -173,70 +173,70 @@ LLControlVariable::~LLControlVariable() LLSD LLControlVariable::getComparableValue(const LLSD& value) { - // *FIX:MEP - The following is needed to make the LLSD::ImplString - // work with boolean controls... - LLSD storable_value; - if(TYPE_BOOLEAN == type() && value.isString()) - { - BOOL temp; - if(LLStringUtil::convertToBOOL(value.asString(), temp)) - { - storable_value = (bool)temp; - } - else - { - storable_value = false; - } - } - else if (TYPE_LLSD == type() && value.isString()) - { - LLPointer parser = new LLSDNotationParser; - LLSD result; - std::stringstream value_stream(value.asString()); - if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) - { - storable_value = result; - } - else - { - storable_value = value; - } - } - else - { - storable_value = value; - } - - return storable_value; + // *FIX:MEP - The following is needed to make the LLSD::ImplString + // work with boolean controls... + LLSD storable_value; + if(TYPE_BOOLEAN == type() && value.isString()) + { + BOOL temp; + if(LLStringUtil::convertToBOOL(value.asString(), temp)) + { + storable_value = (bool)temp; + } + else + { + storable_value = false; + } + } + else if (TYPE_LLSD == type() && value.isString()) + { + LLPointer parser = new LLSDNotationParser; + LLSD result; + std::stringstream value_stream(value.asString()); + if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) + { + storable_value = result; + } + else + { + storable_value = value; + } + } + else + { + storable_value = value; + } + + return storable_value; } void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) { - if (mValidateSignal(this, new_value) == false) - { - // can not set new value, exit - return; - } - - LLSD storable_value = getComparableValue(new_value); - LLSD original_value = getValue(); - bool value_changed = llsd_compare(original_value, storable_value) == FALSE; - if(saved_value) - { - // If we're going to save this value, return to default but don't fire - resetToDefault(false); - if (llsd_compare(mValues.back(), storable_value) == FALSE) - { - mValues.push_back(storable_value); - } - } + if (mValidateSignal(this, new_value) == false) + { + // can not set new value, exit + return; + } + + LLSD storable_value = getComparableValue(new_value); + LLSD original_value = getValue(); + bool value_changed = llsd_compare(original_value, storable_value) == FALSE; + if(saved_value) + { + // If we're going to save this value, return to default but don't fire + resetToDefault(false); + if (llsd_compare(mValues.back(), storable_value) == FALSE) + { + mValues.push_back(storable_value); + } + } else { // This is an unsaved value. Its needs to reside at - // mValues[2] (or greater). It must not affect + // mValues[2] (or greater). It must not affect // the result of getSaveValue() - if (llsd_compare(mValues.back(), storable_value) == FALSE) - { + if (llsd_compare(mValues.back(), storable_value) == FALSE) + { while(mValues.size() > 2) { // Remove any unsaved values. @@ -251,107 +251,107 @@ void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) // Add the 'un-save' value. mValues.push_back(storable_value); - } + } } if(value_changed) { - firePropertyChanged(original_value); + firePropertyChanged(original_value); } } void LLControlVariable::setDefaultValue(const LLSD& value) { - // Set the control variables value and make it - // the default value. If the active value is changed, - // send the signal. - // *NOTE: Default values are not saved, only read. + // Set the control variables value and make it + // the default value. If the active value is changed, + // send the signal. + // *NOTE: Default values are not saved, only read. - LLSD comparable_value = getComparableValue(value); - LLSD original_value = getValue(); - bool value_changed = (llsd_compare(original_value, comparable_value) == FALSE); - resetToDefault(false); - mValues[0] = comparable_value; - if(value_changed) - { - firePropertyChanged(original_value); - } + LLSD comparable_value = getComparableValue(value); + LLSD original_value = getValue(); + bool value_changed = (llsd_compare(original_value, comparable_value) == FALSE); + resetToDefault(false); + mValues[0] = comparable_value; + if(value_changed) + { + firePropertyChanged(original_value); + } } void LLControlVariable::setPersist(ePersist state) { - mPersist = state; + mPersist = state; } void LLControlVariable::setHiddenFromSettingsEditor(bool hide) { - mHideFromSettingsEditor = hide; + mHideFromSettingsEditor = hide; } void LLControlVariable::setComment(const std::string& comment) { - mComment = comment; + mComment = comment; } void LLControlVariable::resetToDefault(bool fire_signal) { - //The first setting is always the default - //Pop to it and fire off the listener - LLSD originalValue = mValues.back(); + //The first setting is always the default + //Pop to it and fire off the listener + LLSD originalValue = mValues.back(); - while(mValues.size() > 1) - { - mValues.pop_back(); - } - - if(fire_signal) - { - firePropertyChanged(originalValue); - } + while(mValues.size() > 1) + { + mValues.pop_back(); + } + + if(fire_signal) + { + firePropertyChanged(originalValue); + } } bool LLControlVariable::shouldSave(bool nondefault_only) { - // This method is used to decide whether we should save a given - // variable. Two of the three values of mPersist are easy. - if (mPersist == PERSIST_NO) - return false; + // This method is used to decide whether we should save a given + // variable. Two of the three values of mPersist are easy. + if (mPersist == PERSIST_NO) + return false; - if (mPersist == PERSIST_ALWAYS) - return true; + if (mPersist == PERSIST_ALWAYS) + return true; - // PERSIST_NONDFT - // If caller doesn't need us to filter, just save. - if (! nondefault_only) - return true; + // PERSIST_NONDFT + // If caller doesn't need us to filter, just save. + if (! nondefault_only) + return true; - // PERSIST_NONDFT: caller only wants us to save this variable if its value - // differs from default. - if (isDefault()) // never been altered - return false; + // PERSIST_NONDFT: caller only wants us to save this variable if its value + // differs from default. + if (isDefault()) // never been altered + return false; - // We've set at least one other value: compare it to default. Save only if - // they differ. - return ! llsd_compare(getSaveValue(), getDefault()); + // We've set at least one other value: compare it to default. Save only if + // they differ. + return ! llsd_compare(getSaveValue(), getDefault()); } LLSD LLControlVariable::getSaveValue() const { - //The first level of the stack is default - //We assume that the second level is user preferences that should be saved - if(mValues.size() > 1) return mValues[1]; - return mValues[0]; + //The first level of the stack is default + //We assume that the second level is user preferences that should be saved + if(mValues.size() > 1) return mValues[1]; + return mValues[0]; } LLPointer LLControlGroup::getControl(const std::string& name) { - if (mSettingsProfile) - { - incrCount(name); - } + if (mSettingsProfile) + { + incrCount(name); + } - ctrl_name_table_t::iterator iter = mNameTable.find(name); - return iter == mNameTable.end() ? LLPointer() : iter->second; + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter == mNameTable.end() ? LLPointer() : iter->second; } @@ -373,296 +373,296 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32" }; LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker(name), - mSettingsProfile(false) +: LLInstanceTracker(name), + mSettingsProfile(false) { - if (NULL != getenv("LL_SETTINGS_PROFILE")) - { - mSettingsProfile = true; - } + if (NULL != getenv("LL_SETTINGS_PROFILE")) + { + mSettingsProfile = true; + } } LLControlGroup::~LLControlGroup() { - cleanup(); + cleanup(); } static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs) { - return lhs.second > rhs.second; + return lhs.second > rhs.second; }; void LLControlGroup::cleanup() { - if(mSettingsProfile && getCount.size() != 0) - { - std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); - LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ - if(!out) - { - LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; - } - else - { - F64 end_time = LLTimer::getTotalSeconds(); - U32 total_seconds = (U32)(end_time - start_time); - - std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds); - std::ostringstream data_msg; - - data_msg << msg; - size_t data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) - { - LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; - } - - for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) - { - getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); - } - sort(getCount_v.begin(), getCount_v.end(), compareRoutine); - - for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) - { - U32 access_rate = 0; - if (total_seconds != 0) - { - access_rate = iter->second / total_seconds; - } - if (access_rate >= 2) - { - std::ostringstream data_msg; - msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str()); - data_msg << msg << "\n"; - size_t data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) - { - LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; - } - } - } - getCount = LLSD::emptyMap(); - fclose(out); - } - } - - mNameTable.clear(); + if(mSettingsProfile && getCount.size() != 0) + { + std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); + LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ + if(!out) + { + LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; + } + else + { + F64 end_time = LLTimer::getTotalSeconds(); + U32 total_seconds = (U32)(end_time - start_time); + + std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds); + std::ostringstream data_msg; + + data_msg << msg; + size_t data_size = data_msg.str().size(); + if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) + { + LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; + } + + for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) + { + getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); + } + sort(getCount_v.begin(), getCount_v.end(), compareRoutine); + + for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) + { + U32 access_rate = 0; + if (total_seconds != 0) + { + access_rate = iter->second / total_seconds; + } + if (access_rate >= 2) + { + std::ostringstream data_msg; + msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str()); + data_msg << msg << "\n"; + size_t data_size = data_msg.str().size(); + if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) + { + LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; + } + } + } + getCount = LLSD::emptyMap(); + fclose(out); + } + } + + mNameTable.clear(); } eControlType LLControlGroup::typeStringToEnum(const std::string& typestr) { - for(int i = 0; i < (int)TYPE_COUNT; ++i) - { - if(mTypeString[i] == typestr) return (eControlType)i; - } - return (eControlType)-1; + for(int i = 0; i < (int)TYPE_COUNT; ++i) + { + if(mTypeString[i] == typestr) return (eControlType)i; + } + return (eControlType)-1; } std::string LLControlGroup::typeEnumToString(eControlType typeenum) { - return mTypeString[typeenum]; + return mTypeString[typeenum]; } LLControlVariable* LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor) { - LLControlVariable* existing_control = getControl(name); - if (existing_control) - { - if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type)) - { - if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val)) - { - // Sometimes we need to declare a control *after* it has been loaded from a settings file. - LLSD cur_value = existing_control->getValue(); // get the current value - existing_control->setDefaultValue(initial_val); // set the default to the declared value - existing_control->setValue(cur_value); // now set to the loaded value - } - } - else - { - LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; - } - return existing_control; - } - - // if not, create the control and add it to the name table - LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor); - mNameTable[name] = control; - return control; + LLControlVariable* existing_control = getControl(name); + if (existing_control) + { + if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type)) + { + if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val)) + { + // Sometimes we need to declare a control *after* it has been loaded from a settings file. + LLSD cur_value = existing_control->getValue(); // get the current value + existing_control->setDefaultValue(initial_val); // set the default to the declared value + existing_control->setValue(cur_value); // now set to the loaded value + } + } + else + { + LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; + } + return existing_control; + } + + // if not, create the control and add it to the name table + LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor); + mNameTable[name] = control; + return control; } LLControlVariable* LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist); + return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_S32, initial_val, comment, persist); + return declareControl(name, TYPE_S32, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_F32, initial_val, comment, persist); + return declareControl(name, TYPE_F32, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareBOOL(const std::string& name, const BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist); + return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_STRING, initial_val, comment, persist); + return declareControl(name, TYPE_STRING, initial_val, comment, persist); } LLControlVariable* LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist) { - return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) { - return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) { - return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); + return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); } LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) { - return declareControl(name, TYPE_LLSD, initial_val, comment, persist); + return declareControl(name, TYPE_LLSD, initial_val, comment, persist); } void LLControlGroup::incrCount(const std::string& name) { - if (0.0 == start_time) - { - start_time = LLTimer::getTotalSeconds(); - } - getCount[name] = getCount[name].asInteger() + 1; + if (0.0 == start_time) + { + start_time = LLTimer::getTotalSeconds(); + } + getCount[name] = getCount[name].asInteger() + 1; } BOOL LLControlGroup::getBOOL(const std::string& name) { - return (BOOL)get(name); + return (BOOL)get(name); } S32 LLControlGroup::getS32(const std::string& name) { - return get(name); + return get(name); } U32 LLControlGroup::getU32(const std::string& name) { - return get(name); + return get(name); } F32 LLControlGroup::getF32(const std::string& name) { - return get(name); + return get(name); } std::string LLControlGroup::getString(const std::string& name) { - return get(name); + return get(name); } LLWString LLControlGroup::getWString(const std::string& name) { - return get(name); + return get(name); } std::string LLControlGroup::getText(const std::string& name) { - std::string utf8_string = getString(name); - LLStringUtil::replaceChar(utf8_string, '^', '\n'); - LLStringUtil::replaceChar(utf8_string, '%', ' '); - return (utf8_string); + std::string utf8_string = getString(name); + LLStringUtil::replaceChar(utf8_string, '^', '\n'); + LLStringUtil::replaceChar(utf8_string, '%', ' '); + return (utf8_string); } LLVector3 LLControlGroup::getVector3(const std::string& name) { - return get(name); + return get(name); } LLVector3d LLControlGroup::getVector3d(const std::string& name) { - return get(name); + return get(name); } LLQuaternion LLControlGroup::getQuaternion(const std::string& name) { - return get(name); + return get(name); } LLRect LLControlGroup::getRect(const std::string& name) { - return get(name); + return get(name); } LLColor4 LLControlGroup::getColor(const std::string& name) { - return get(name); + return get(name); } LLColor4 LLControlGroup::getColor4(const std::string& name) { - return get(name); + return get(name); } LLColor3 LLControlGroup::getColor3(const std::string& name) { - return get(name); + return get(name); } LLSD LLControlGroup::getLLSD(const std::string& name) { - return get(name); + return get(name); } LLSD LLControlGroup::asLLSD(bool diffs_only) { - // Dump all stored values as LLSD - LLSD result = LLSD::emptyArray(); - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - LLControlVariable *control = iter->second; - if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) - { - continue; - } - const std::string& name = iter->first; - result[name] = getLLSD(name); - } - return result; + // Dump all stored values as LLSD + LLSD result = LLSD::emptyArray(); + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + LLControlVariable *control = iter->second; + if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) + { + continue; + } + const std::string& name = iter->first; + result[name] = getLLSD(name); + } + return result; } BOOL LLControlGroup::controlExists(const std::string& name) { - ctrl_name_table_t::iterator iter = mNameTable.find(name); - return iter != mNameTable.end(); + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter != mNameTable.end(); } @@ -672,81 +672,81 @@ BOOL LLControlGroup::controlExists(const std::string& name) void LLControlGroup::setBOOL(const std::string& name, BOOL val) { - set(name, val); + set(name, val); } void LLControlGroup::setS32(const std::string& name, S32 val) { - set(name, val); + set(name, val); } void LLControlGroup::setF32(const std::string& name, F32 val) { - set(name, val); + set(name, val); } void LLControlGroup::setU32(const std::string& name, U32 val) { - set(name, val); + set(name, val); } void LLControlGroup::setString(const std::string& name, const std::string &val) { - set(name, val); + set(name, val); } void LLControlGroup::setVector3(const std::string& name, const LLVector3 &val) { - set(name, val); + set(name, val); } void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val) { - set(name, val); + set(name, val); } void LLControlGroup::setQuaternion(const std::string& name, const LLQuaternion &val) { - set(name, val); + set(name, val); } void LLControlGroup::setRect(const std::string& name, const LLRect &val) { - set(name, val); + set(name, val); } void LLControlGroup::setColor4(const std::string& name, const LLColor4 &val) { - set(name, val); + set(name, val); } void LLControlGroup::setLLSD(const std::string& name, const LLSD& val) { - set(name, val); + set(name, val); } void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val, bool saved_value) { - if (name.empty()) - { - return; - } + if (name.empty()) + { + return; + } + + LLControlVariable* control = getControl(name); - LLControlVariable* control = getControl(name); - - if (control) - { - control->setValue(val, saved_value); - } - else - { - CONTROL_ERRS << "Invalid control " << name << LL_ENDL; - } + if (control) + { + control->setValue(val, saved_value); + } + else + { + CONTROL_ERRS << "Invalid control " << name << LL_ENDL; + } } @@ -757,388 +757,388 @@ void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val, b // Returns number of controls loaded, so 0 if failure U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require_declaration, eControlType declare_as) { - std::string name; - - LLXmlTree xml_controls; - - if (!xml_controls.parseFile(filename)) - { - LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL; - return 0; - } - - LLXmlTreeNode* rootp = xml_controls.getRoot(); - if (!rootp || !rootp->hasAttribute("version")) - { - LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL; - return 0; - } - - U32 validitems = 0; - S32 version; - - rootp->getAttributeS32("version", version); - - // Check file version - if (version != CURRENT_VERSION) - { - LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; - return 0; - } - - LLXmlTreeNode* child_nodep = rootp->getFirstChild(); - while(child_nodep) - { - name = child_nodep->getName(); - - BOOL declared = controlExists(name); - - if (require_declaration && !declared) - { - // Declaration required, but this name not declared. - // Complain about non-empty names. - if (!name.empty()) - { - //read in to end of line - LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; - } - child_nodep = rootp->getNextChild(); - continue; - } - - // Got an item. Load it up. - // If not declared, assume it's a string - if (!declared) - { - switch(declare_as) - { - case TYPE_COL4: - declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO); - break; - case TYPE_STRING: - default: - declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO); - break; - } - } - - // Control name has been declared in code. - LLControlVariable *control = getControl(name); - - llassert(control); - - switch(control->mType) - { - case TYPE_F32: - { - F32 initial = 0.f; - - child_nodep->getAttributeF32("value", initial); - - control->set(initial); - validitems++; - } - break; - case TYPE_S32: - { - S32 initial = 0; - - child_nodep->getAttributeS32("value", initial); - - control->set(initial); - validitems++; - } - break; - case TYPE_U32: - { - U32 initial = 0; - child_nodep->getAttributeU32("value", initial); - control->set((LLSD::Integer) initial); - validitems++; - } - break; - case TYPE_BOOLEAN: - { - BOOL initial = FALSE; - - child_nodep->getAttributeBOOL("value", initial); - control->set(initial); - - validitems++; - } - break; - case TYPE_STRING: - { - std::string string; - child_nodep->getAttributeString("value", string); - control->set(string); - validitems++; - } - break; - case TYPE_VEC3: - { - LLVector3 vector; - - child_nodep->getAttributeVector3("value", vector); - control->set(vector.getValue()); - validitems++; - } - break; - case TYPE_VEC3D: - { - LLVector3d vector; - - child_nodep->getAttributeVector3d("value", vector); - - control->set(vector.getValue()); - validitems++; - } - break; - case TYPE_QUAT: - { - LLQuaternion quat; - - child_nodep->getAttributeQuat("value", quat); - - control->set(quat.getValue()); - validitems++; - } - break; - case TYPE_RECT: - { - //RN: hack to support reading rectangles from a string - std::string rect_string; - - child_nodep->getAttributeString("value", rect_string); - std::istringstream istream(rect_string); - S32 left, bottom, width, height; - - istream >> left >> bottom >> width >> height; - - LLRect rect; - rect.setOriginAndSize(left, bottom, width, height); - - control->set(rect.getValue()); - validitems++; - } - break; - case TYPE_COL4: - { - LLColor4 color; - - child_nodep->getAttributeColor4("value", color); - control->set(color.getValue()); - validitems++; - } - break; - case TYPE_COL3: - { - LLVector3 color; - - child_nodep->getAttributeVector3("value", color); - control->set(LLColor3(color.mV).getValue()); - validitems++; - } - break; - - default: - break; - - } - - child_nodep = rootp->getNextChild(); - } - - return validitems; + std::string name; + + LLXmlTree xml_controls; + + if (!xml_controls.parseFile(filename)) + { + LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL; + return 0; + } + + LLXmlTreeNode* rootp = xml_controls.getRoot(); + if (!rootp || !rootp->hasAttribute("version")) + { + LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL; + return 0; + } + + U32 validitems = 0; + S32 version; + + rootp->getAttributeS32("version", version); + + // Check file version + if (version != CURRENT_VERSION) + { + LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; + return 0; + } + + LLXmlTreeNode* child_nodep = rootp->getFirstChild(); + while(child_nodep) + { + name = child_nodep->getName(); + + BOOL declared = controlExists(name); + + if (require_declaration && !declared) + { + // Declaration required, but this name not declared. + // Complain about non-empty names. + if (!name.empty()) + { + //read in to end of line + LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; + } + child_nodep = rootp->getNextChild(); + continue; + } + + // Got an item. Load it up. + // If not declared, assume it's a string + if (!declared) + { + switch(declare_as) + { + case TYPE_COL4: + declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO); + break; + case TYPE_STRING: + default: + declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO); + break; + } + } + + // Control name has been declared in code. + LLControlVariable *control = getControl(name); + + llassert(control); + + switch(control->mType) + { + case TYPE_F32: + { + F32 initial = 0.f; + + child_nodep->getAttributeF32("value", initial); + + control->set(initial); + validitems++; + } + break; + case TYPE_S32: + { + S32 initial = 0; + + child_nodep->getAttributeS32("value", initial); + + control->set(initial); + validitems++; + } + break; + case TYPE_U32: + { + U32 initial = 0; + child_nodep->getAttributeU32("value", initial); + control->set((LLSD::Integer) initial); + validitems++; + } + break; + case TYPE_BOOLEAN: + { + BOOL initial = FALSE; + + child_nodep->getAttributeBOOL("value", initial); + control->set(initial); + + validitems++; + } + break; + case TYPE_STRING: + { + std::string string; + child_nodep->getAttributeString("value", string); + control->set(string); + validitems++; + } + break; + case TYPE_VEC3: + { + LLVector3 vector; + + child_nodep->getAttributeVector3("value", vector); + control->set(vector.getValue()); + validitems++; + } + break; + case TYPE_VEC3D: + { + LLVector3d vector; + + child_nodep->getAttributeVector3d("value", vector); + + control->set(vector.getValue()); + validitems++; + } + break; + case TYPE_QUAT: + { + LLQuaternion quat; + + child_nodep->getAttributeQuat("value", quat); + + control->set(quat.getValue()); + validitems++; + } + break; + case TYPE_RECT: + { + //RN: hack to support reading rectangles from a string + std::string rect_string; + + child_nodep->getAttributeString("value", rect_string); + std::istringstream istream(rect_string); + S32 left, bottom, width, height; + + istream >> left >> bottom >> width >> height; + + LLRect rect; + rect.setOriginAndSize(left, bottom, width, height); + + control->set(rect.getValue()); + validitems++; + } + break; + case TYPE_COL4: + { + LLColor4 color; + + child_nodep->getAttributeColor4("value", color); + control->set(color.getValue()); + validitems++; + } + break; + case TYPE_COL3: + { + LLVector3 color; + + child_nodep->getAttributeVector3("value", color); + control->set(LLColor3(color.mV).getValue()); + validitems++; + } + break; + + default: + break; + + } + + child_nodep = rootp->getNextChild(); + } + + return validitems; } U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { - LLSD settings; - int num_saved = 0; - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - LLControlVariable* control = iter->second; - if (!control) - { - LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL; - } - else if( control->shouldSave(nondefault_only) ) - { - settings[iter->first]["Type"] = typeEnumToString(control->type()); - settings[iter->first]["Comment"] = control->getComment(); - settings[iter->first]["Value"] = control->getSaveValue(); - ++num_saved; - } - } - llofstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::toPrettyXML(settings, file); - file.close(); - LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL; - } - else - { + LLSD settings; + int num_saved = 0; + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + LLControlVariable* control = iter->second; + if (!control) + { + LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL; + } + else if( control->shouldSave(nondefault_only) ) + { + settings[iter->first]["Type"] = typeEnumToString(control->type()); + settings[iter->first]["Comment"] = control->getComment(); + settings[iter->first]["Value"] = control->getSaveValue(); + ++num_saved; + } + } + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(settings, file); + file.close(); + 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... - LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL; - return 0; - } - return num_saved; + LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL; + return 0; + } + return num_saved; } U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values) { - LLSD settings; - llifstream infile; - infile.open(filename.c_str()); - if(!infile.is_open()) - { - LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL; - return 0; - } - - if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile)) - { - infile.close(); - LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; - return loadFromFileLegacy(filename, TRUE, TYPE_STRING); - } - - U32 validitems = 0; - bool hidefromsettingseditor = false; - - for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) - { - LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT; - std::string const & name = itr->first; - LLSD const & control_map = itr->second; - - if(control_map.has("Persist")) - { - persist = control_map["Persist"].asInteger()? - LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO; - } - - // Sometimes we want to use the settings system to provide cheap persistence, but we - // don't want the settings themselves to be easily manipulated in the UI because - // doing so can cause support problems. So we have this option: - if(control_map.has("HideFromEditor")) - { - hidefromsettingseditor = control_map["HideFromEditor"].asInteger(); - } - else - { - hidefromsettingseditor = false; - } - - // If the control exists just set the value from the input file. - LLControlVariable* existing_control = getControl(name); - if(existing_control) - { - // set_default_values is true when we're loading the initial, - // immutable files from app_settings, e.g. settings.xml. - if(set_default_values) - { - // Override all previously set properties of this control. - // ... except for type. The types must match. - eControlType new_type = typeStringToEnum(control_map["Type"].asString()); - if(existing_control->isType(new_type)) - { - existing_control->setDefaultValue(control_map["Value"]); - existing_control->setPersist(persist); - existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor); - existing_control->setComment(control_map["Comment"].asString()); - } - else - { - LL_ERRS() << "Mismatched type of control variable '" - << name << "' found while loading '" - << filename << "'." << LL_ENDL; - } - } - else if(existing_control->isPersisted()) - { - // save_values is specifically false for (e.g.) - // SessionSettingsFile and UserSessionSettingsFile -- in other - // words, for a file that's supposed to be transient. - existing_control->setValue(control_map["Value"], save_values); - } - // *NOTE: If not persisted and not setting defaults, - // the value should not get loaded. - } - else - { - // We've never seen this control before. Either we're loading up - // the initial set of default settings files (set_default_values) - // -- or we're loading user settings last saved by a viewer that - // supports a superset of the variables we know. - // CHOP-962: if we're loading an unrecognized user setting, make - // sure we save it later. If you try an experimental viewer, tweak - // a new setting, briefly revert to an old viewer, then return to - // the new one, we don't want the old viewer to discard the - // setting you changed. - if (! set_default_values) - { - // Using PERSIST_ALWAYS insists that saveToFile() (which calls - // LLControlVariable::shouldSave()) must save this control - // variable regardless of its value. We can safely set this - // LLControlVariable persistent because the 'persistent' flag - // is not itself persisted! - persist = LLControlVariable::PERSIST_ALWAYS; - // We want to mention unrecognized user settings variables - // (e.g. from a newer version of the viewer) in the log. But - // we also arrive here for Boolean variables generated by - // the notifications subsystem when the user checks "Don't - // show me this again." These aren't declared in settings.xml; - // they're actually named for the notification they suppress. - // We don't want to mention those. Apologies, this is a bit of - // a hack: we happen to know that user settings go into an - // LLControlGroup whose name is "Global". - if (getKey() == "Global") - { - LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey() - << " settings variable " << name << LL_ENDL; - } - } - - declareControl(name, - typeStringToEnum(control_map["Type"].asString()), - control_map["Value"], - control_map["Comment"].asString(), - persist, - hidefromsettingseditor - ); - } - - ++validitems; - } - - LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL; - return validitems; + LLSD settings; + llifstream infile; + infile.open(filename.c_str()); + if(!infile.is_open()) + { + LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL; + return 0; + } + + if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile)) + { + infile.close(); + LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; + return loadFromFileLegacy(filename, TRUE, TYPE_STRING); + } + + U32 validitems = 0; + bool hidefromsettingseditor = false; + + for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) + { + LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT; + std::string const & name = itr->first; + LLSD const & control_map = itr->second; + + if(control_map.has("Persist")) + { + persist = control_map["Persist"].asInteger()? + LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO; + } + + // Sometimes we want to use the settings system to provide cheap persistence, but we + // don't want the settings themselves to be easily manipulated in the UI because + // doing so can cause support problems. So we have this option: + if(control_map.has("HideFromEditor")) + { + hidefromsettingseditor = control_map["HideFromEditor"].asInteger(); + } + else + { + hidefromsettingseditor = false; + } + + // If the control exists just set the value from the input file. + LLControlVariable* existing_control = getControl(name); + if(existing_control) + { + // set_default_values is true when we're loading the initial, + // immutable files from app_settings, e.g. settings.xml. + if(set_default_values) + { + // Override all previously set properties of this control. + // ... except for type. The types must match. + eControlType new_type = typeStringToEnum(control_map["Type"].asString()); + if(existing_control->isType(new_type)) + { + existing_control->setDefaultValue(control_map["Value"]); + existing_control->setPersist(persist); + existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor); + existing_control->setComment(control_map["Comment"].asString()); + } + else + { + LL_ERRS() << "Mismatched type of control variable '" + << name << "' found while loading '" + << filename << "'." << LL_ENDL; + } + } + else if(existing_control->isPersisted()) + { + // save_values is specifically false for (e.g.) + // SessionSettingsFile and UserSessionSettingsFile -- in other + // words, for a file that's supposed to be transient. + existing_control->setValue(control_map["Value"], save_values); + } + // *NOTE: If not persisted and not setting defaults, + // the value should not get loaded. + } + else + { + // We've never seen this control before. Either we're loading up + // the initial set of default settings files (set_default_values) + // -- or we're loading user settings last saved by a viewer that + // supports a superset of the variables we know. + // CHOP-962: if we're loading an unrecognized user setting, make + // sure we save it later. If you try an experimental viewer, tweak + // a new setting, briefly revert to an old viewer, then return to + // the new one, we don't want the old viewer to discard the + // setting you changed. + if (! set_default_values) + { + // Using PERSIST_ALWAYS insists that saveToFile() (which calls + // LLControlVariable::shouldSave()) must save this control + // variable regardless of its value. We can safely set this + // LLControlVariable persistent because the 'persistent' flag + // is not itself persisted! + persist = LLControlVariable::PERSIST_ALWAYS; + // We want to mention unrecognized user settings variables + // (e.g. from a newer version of the viewer) in the log. But + // we also arrive here for Boolean variables generated by + // the notifications subsystem when the user checks "Don't + // show me this again." These aren't declared in settings.xml; + // they're actually named for the notification they suppress. + // We don't want to mention those. Apologies, this is a bit of + // a hack: we happen to know that user settings go into an + // LLControlGroup whose name is "Global". + if (getKey() == "Global") + { + LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey() + << " settings variable " << name << LL_ENDL; + } + } + + declareControl(name, + typeStringToEnum(control_map["Type"].asString()), + control_map["Value"], + control_map["Comment"].asString(), + persist, + hidefromsettingseditor + ); + } + + ++validitems; + } + + LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL; + return validitems; } void LLControlGroup::resetToDefaults() { - ctrl_name_table_t::iterator control_iter; - for (control_iter = mNameTable.begin(); - control_iter != mNameTable.end(); - ++control_iter) - { - LLControlVariable* control = (*control_iter).second; - control->resetToDefault(); - } + ctrl_name_table_t::iterator control_iter; + for (control_iter = mNameTable.begin(); + control_iter != mNameTable.end(); + ++control_iter) + { + LLControlVariable* control = (*control_iter).second; + control->resetToDefault(); + } } void LLControlGroup::applyToAll(ApplyFunctor* func) { - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - func->apply(iter->first, iter->second); - } + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); + iter != mNameTable.end(); iter++) + { + func->apply(iter->first, iter->second); + } } //============================================================================ @@ -1146,335 +1146,335 @@ void LLControlGroup::applyToAll(ApplyFunctor* func) #ifdef TEST_HARNESS void main() { - F32_CONTROL foo, getfoo; + F32_CONTROL foo, getfoo; + + S32_CONTROL bar, getbar; - S32_CONTROL bar, getbar; - - BOOL_CONTROL baz; + BOOL_CONTROL baz; - U32 count = gGlobals.loadFromFile("controls.ini"); - LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL; + U32 count = gGlobals.loadFromFile("controls.ini"); + LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL; - // test insertion - foo = new LLControlVariable("gFoo", 5.f, 1.f, 20.f); - gGlobals.addEntry("gFoo", foo); + // test insertion + foo = new LLControlVariable("gFoo", 5.f, 1.f, 20.f); + gGlobals.addEntry("gFoo", foo); - bar = new LLControlVariable("gBar", 10, 2, 22); - gGlobals.addEntry("gBar", bar); + bar = new LLControlVariable("gBar", 10, 2, 22); + gGlobals.addEntry("gBar", bar); - baz = new LLControlVariable("gBaz", FALSE); - gGlobals.addEntry("gBaz", baz); + baz = new LLControlVariable("gBaz", FALSE); + gGlobals.addEntry("gBaz", baz); - // test retrieval - getfoo = (LLControlVariable*) gGlobals.resolveName("gFoo"); - getfoo->dump(); + // test retrieval + getfoo = (LLControlVariable*) gGlobals.resolveName("gFoo"); + getfoo->dump(); - getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); - getbar->dump(); + getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); + getbar->dump(); - // change data - getfoo->set(10.f); - getfoo->dump(); + // change data + getfoo->set(10.f); + getfoo->dump(); - // Failure modes + // Failure modes - // ...min > max - // badfoo = new LLControlVariable("gFoo2", 100.f, 20.f, 5.f); + // ...min > max + // badfoo = new LLControlVariable("gFoo2", 100.f, 20.f, 5.f); - // ...initial > max - // badbar = new LLControlVariable("gBar2", 10, 20, 100000); + // ...initial > max + // badbar = new LLControlVariable("gBar2", 10, 20, 100000); - // ...misspelled name - // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); - // getfoo->dump(); + // ...misspelled name + // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); + // getfoo->dump(); - // ...invalid data type - getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo"); - getfoo->set(TRUE); - getfoo->dump(); + // ...invalid data type + getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo"); + getfoo->set(TRUE); + getfoo->dump(); - // ...out of range data - // getfoo->set(100000000.f); - // getfoo->dump(); + // ...out of range data + // getfoo->set(100000000.f); + // getfoo->dump(); - // Clean Up - delete foo; - delete bar; - delete baz; + // Clean Up + delete foo; + delete bar; + delete baz; } #endif -template <> eControlType get_control_type() -{ - return TYPE_U32; +template <> eControlType get_control_type() +{ + return TYPE_U32; } -template <> eControlType get_control_type() -{ - return TYPE_S32; +template <> eControlType get_control_type() +{ + return TYPE_S32; } -template <> eControlType get_control_type() -{ - return TYPE_F32; +template <> eControlType get_control_type() +{ + return TYPE_F32; } -template <> eControlType get_control_type () -{ - return TYPE_BOOLEAN; +template <> eControlType get_control_type () +{ + return TYPE_BOOLEAN; } /* // Yay BOOL, its really an S32. -template <> eControlType get_control_type () -{ - return TYPE_BOOLEAN; +template <> eControlType get_control_type () +{ + return TYPE_BOOLEAN; } */ -template <> eControlType get_control_type() -{ - return TYPE_STRING; +template <> eControlType get_control_type() +{ + return TYPE_STRING; } -template <> eControlType get_control_type() -{ - return TYPE_VEC3; +template <> eControlType get_control_type() +{ + return TYPE_VEC3; } -template <> eControlType get_control_type() -{ - return TYPE_VEC3D; +template <> eControlType get_control_type() +{ + return TYPE_VEC3D; } template <> eControlType get_control_type() { - return TYPE_QUAT; + return TYPE_QUAT; } -template <> eControlType get_control_type() -{ - return TYPE_RECT; +template <> eControlType get_control_type() +{ + return TYPE_RECT; } -template <> eControlType get_control_type() -{ - return TYPE_COL4; +template <> eControlType get_control_type() +{ + return TYPE_COL4; } -template <> eControlType get_control_type() -{ - return TYPE_COL3; +template <> eControlType get_control_type() +{ + return TYPE_COL3; } -template <> eControlType get_control_type() -{ - return TYPE_LLSD; +template <> eControlType get_control_type() +{ + return TYPE_LLSD; } -template <> LLSD convert_to_llsd(const U32& in) -{ - return (LLSD::Integer)in; +template <> LLSD convert_to_llsd(const U32& in) +{ + return (LLSD::Integer)in; } -template <> LLSD convert_to_llsd(const LLVector3& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd(const LLVector3& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd(const LLVector3d& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd(const LLVector3d& in) +{ + return in.getValue(); } template <> LLSD convert_to_llsd(const LLQuaternion& in) { - return in.getValue(); + return in.getValue(); } -template <> LLSD convert_to_llsd(const LLRect& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd(const LLRect& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd(const LLColor4& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd(const LLColor4& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd(const LLColor3& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd(const LLColor3& in) +{ + return in.getValue(); } -template <> LLSD convert_to_llsd(const LLColor4U& in) -{ - return in.getValue(); +template <> LLSD convert_to_llsd(const LLColor4U& in) +{ + return in.getValue(); } template<> bool convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_BOOLEAN) - return sd.asBoolean(); - else - { - CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return FALSE; - } + if (type == TYPE_BOOLEAN) + return sd.asBoolean(); + else + { + CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return FALSE; + } } template<> S32 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_S32) - return sd.asInteger(); - else - { - CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0; - } + if (type == TYPE_S32) + return sd.asInteger(); + else + { + CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return 0; + } } template<> U32 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_U32) - return sd.asInteger(); - else - { - CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0; - } + if (type == TYPE_U32) + return sd.asInteger(); + else + { + CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return 0; + } } template<> F32 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_F32) - return (F32) sd.asReal(); - else - { - CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0.0f; - } + if (type == TYPE_F32) + return (F32) sd.asReal(); + else + { + CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return 0.0f; + } } template<> std::string convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_STRING) - return sd.asString(); - else - { - CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLStringUtil::null; - } + if (type == TYPE_STRING) + return sd.asString(); + else + { + CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLStringUtil::null; + } } template<> LLWString convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - return utf8str_to_wstring(convert_from_llsd(sd, type, control_name)); + return utf8str_to_wstring(convert_from_llsd(sd, type, control_name)); } template<> LLVector3 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_VEC3) - return (LLVector3)sd; - else - { - CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLVector3::zero; - } + if (type == TYPE_VEC3) + return (LLVector3)sd; + else + { + CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLVector3::zero; + } } template<> LLVector3d convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_VEC3D) - return (LLVector3d)sd; - else - { - CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLVector3d::zero; - } + if (type == TYPE_VEC3D) + return (LLVector3d)sd; + else + { + CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLVector3d::zero; + } } template<> LLQuaternion convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_QUAT) - return (LLQuaternion)sd; - else - { - CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLQuaternion(); - } + if (type == TYPE_QUAT) + return (LLQuaternion)sd; + else + { + CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLQuaternion(); + } } template<> LLRect convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_RECT) - return LLRect(sd); - else - { - CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLRect::null; - } + if (type == TYPE_RECT) + return LLRect(sd); + else + { + CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLRect::null; + } } template<> LLColor4 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_COL4) - { - LLColor4 color(sd); - if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) - { - 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) - { - 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) - { - 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) - { - LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; - } - - return LLColor4(sd); - } - else - { - CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; - return LLColor4::white; - } + if (type == TYPE_COL4) + { + LLColor4 color(sd); + if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) + { + 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) + { + 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) + { + 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) + { + LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; + } + + return LLColor4(sd); + } + else + { + CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; + return LLColor4::white; + } } template<> LLColor3 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - if (type == TYPE_COL3) - return sd; - else - { - CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLColor3::white; - } + if (type == TYPE_COL3) + return sd; + else + { + CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; + return LLColor3::white; + } } template<> LLSD convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - return sd; + return sd; } @@ -1502,21 +1502,21 @@ static LLCachedControl test_BrowserHomePage("BrowserHomePage", "hah void test_cached_control() { #define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL - TEST_LLCC(U32, 666); - TEST_LLCC(S32, (S32)-666); - TEST_LLCC(F32, (F32)-666.666); - TEST_LLCC(bool, true); - TEST_LLCC(BOOL, FALSE); - if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; - TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); - TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); - TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); - TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); - TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); - TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); -//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); - - if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; + TEST_LLCC(U32, 666); + TEST_LLCC(S32, (S32)-666); + TEST_LLCC(F32, (F32)-666.666); + TEST_LLCC(bool, true); + TEST_LLCC(BOOL, FALSE); + if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; + TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); + TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); + TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); + TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); + TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); + TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); +//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); + + if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; } #endif // TEST_CACHED_CONTROL diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 5a8d688892..62b0c12770 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -1,25 +1,25 @@ -/** +/** * @file llcontrol.h * @brief A mechanism for storing "control state" for a program * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,13 +48,13 @@ #include #if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) #endif #include #if LL_WINDOWS - #pragma warning (pop) + #pragma warning (pop) #endif #if LL_WINDOWS @@ -72,241 +72,241 @@ class LLColor3; // if this is changed, also modify mTypeString in llcontrol.h typedef enum e_control_type { - TYPE_U32 = 0, - TYPE_S32, - TYPE_F32, - TYPE_BOOLEAN, - TYPE_STRING, - TYPE_VEC3, - TYPE_VEC3D, - TYPE_QUAT, - TYPE_RECT, - TYPE_COL4, - TYPE_COL3, - TYPE_LLSD, - TYPE_COUNT + TYPE_U32 = 0, + TYPE_S32, + TYPE_F32, + TYPE_BOOLEAN, + TYPE_STRING, + TYPE_VEC3, + TYPE_VEC3D, + TYPE_QUAT, + TYPE_RECT, + TYPE_COL4, + TYPE_COL3, + TYPE_LLSD, + TYPE_COUNT } eControlType; class LLControlVariable : public LLRefCount { - LOG_CLASS(LLControlVariable); + LOG_CLASS(LLControlVariable); + + friend class LLControlGroup; - friend class LLControlGroup; - public: - typedef boost::signals2::signal validate_signal_t; - typedef boost::signals2::signal commit_signal_t; + typedef boost::signals2::signal validate_signal_t; + typedef boost::signals2::signal commit_signal_t; - enum ePersist - { - PERSIST_NO, // don't save this var - PERSIST_NONDFT, // save this var if differs from default - PERSIST_ALWAYS // save this var even if has default value - }; + enum ePersist + { + PERSIST_NO, // don't save this var + PERSIST_NONDFT, // save this var if differs from default + PERSIST_ALWAYS // save this var even if has default value + }; private: - std::string mName; - std::string mComment; - eControlType mType; - ePersist mPersist; - bool mHideFromSettingsEditor; - std::vector mValues; - - commit_signal_t mCommitSignal; - validate_signal_t mValidateSignal; - + std::string mName; + std::string mComment; + eControlType mType; + ePersist mPersist; + bool mHideFromSettingsEditor; + std::vector mValues; + + commit_signal_t mCommitSignal; + validate_signal_t mValidateSignal; + public: - LLControlVariable(const std::string& name, eControlType type, - LLSD initial, const std::string& comment, - ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false); - - virtual ~LLControlVariable(); - - const std::string& getName() const { return mName; } - const std::string& getComment() const { return mComment; } - - eControlType type() { return mType; } - bool isType(eControlType tp) { return tp == mType; } - - void resetToDefault(bool fire_signal = false); - - commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal - commit_signal_t* getCommitSignal() { return &mCommitSignal; } - validate_signal_t* getValidateSignal() { return &mValidateSignal; } - - bool isDefault() { return (mValues.size() == 1); } - bool shouldSave(bool nondefault_only); - bool isPersisted() { return mPersist != PERSIST_NO; } - bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; } - LLSD get() const { return getValue(); } - LLSD getValue() const { return mValues.back(); } - LLSD getDefault() const { return mValues.front(); } - LLSD getSaveValue() const; - - void set(const LLSD& val, bool saved_value = true) { setValue(val, saved_value); } - void setValue(const LLSD& value, bool saved_value = TRUE); - void setDefaultValue(const LLSD& value); - void setPersist(ePersist); - void setHiddenFromSettingsEditor(bool hide); - void setComment(const std::string& comment); + LLControlVariable(const std::string& name, eControlType type, + LLSD initial, const std::string& comment, + ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false); + + virtual ~LLControlVariable(); + + const std::string& getName() const { return mName; } + const std::string& getComment() const { return mComment; } + + eControlType type() { return mType; } + bool isType(eControlType tp) { return tp == mType; } + + void resetToDefault(bool fire_signal = false); + + commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal + commit_signal_t* getCommitSignal() { return &mCommitSignal; } + validate_signal_t* getValidateSignal() { return &mValidateSignal; } + + bool isDefault() { return (mValues.size() == 1); } + bool shouldSave(bool nondefault_only); + bool isPersisted() { return mPersist != PERSIST_NO; } + bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; } + LLSD get() const { return getValue(); } + LLSD getValue() const { return mValues.back(); } + LLSD getDefault() const { return mValues.front(); } + LLSD getSaveValue() const; + + void set(const LLSD& val, bool saved_value = true) { setValue(val, saved_value); } + void setValue(const LLSD& value, bool saved_value = TRUE); + void setDefaultValue(const LLSD& value); + void setPersist(ePersist); + void setHiddenFromSettingsEditor(bool hide); + void setComment(const std::string& comment); private: - void firePropertyChanged(const LLSD &pPreviousValue) - { - mCommitSignal(this, mValues.back(), pPreviousValue); - } - LLSD getComparableValue(const LLSD& value); - bool llsd_compare(const LLSD& a, const LLSD & b); + void firePropertyChanged(const LLSD &pPreviousValue) + { + mCommitSignal(this, mValues.back(), pPreviousValue); + } + LLSD getComparableValue(const LLSD& value); + bool llsd_compare(const LLSD& a, const LLSD & b); }; typedef LLPointer LLControlVariablePtr; //! Helper functions for converting between static types and LLControl values -template +template eControlType get_control_type() { - LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL; - return TYPE_COUNT; + LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL; + return TYPE_COUNT; } -template +template LLSD convert_to_llsd(const T& in) { - // default implementation - return LLSD(in); + // default implementation + return LLSD(in); } template T convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) { - // needs specialization - return T(sd); + // needs specialization + return T(sd); } //const U32 STRING_CACHE_SIZE = 10000; class LLControlGroup : public LLInstanceTracker { - LOG_CLASS(LLControlGroup); + LOG_CLASS(LLControlGroup); protected: - typedef std::map ctrl_name_table_t; - ctrl_name_table_t mNameTable; - static const std::string mTypeString[TYPE_COUNT]; + typedef std::map ctrl_name_table_t; + ctrl_name_table_t mNameTable; + static const std::string mTypeString[TYPE_COUNT]; public: - static eControlType typeStringToEnum(const std::string& typestr); - static std::string typeEnumToString(eControlType typeenum); - - LLControlGroup(const std::string& name); - ~LLControlGroup(); - void cleanup(); - - LLControlVariablePtr getControl(const std::string& name); - - struct ApplyFunctor - { - virtual ~ApplyFunctor() {}; - virtual void apply(const std::string& name, LLControlVariable* control) = 0; - }; - void applyToAll(ApplyFunctor* func); - - LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor = FALSE); - LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - - std::string getString(const std::string& name); - std::string getText(const std::string& name); - BOOL getBOOL(const std::string& name); - S32 getS32(const std::string& name); - F32 getF32(const std::string& name); - U32 getU32(const std::string& name); - - LLWString getWString(const std::string& name); - LLVector3 getVector3(const std::string& name); - LLVector3d getVector3d(const std::string& name); - LLRect getRect(const std::string& name); - LLSD getLLSD(const std::string& name); - LLQuaternion getQuaternion(const std::string& name); - - LLColor4 getColor(const std::string& name); - LLColor4 getColor4(const std::string& name); - LLColor3 getColor3(const std::string& name); - - LLSD asLLSD(bool diffs_only); - - // generic getter - template T get(const std::string& name) - { + static eControlType typeStringToEnum(const std::string& typestr); + static std::string typeEnumToString(eControlType typeenum); + + LLControlGroup(const std::string& name); + ~LLControlGroup(); + void cleanup(); + + LLControlVariablePtr getControl(const std::string& name); + + struct ApplyFunctor + { + virtual ~ApplyFunctor() {}; + virtual void apply(const std::string& name, LLControlVariable* control) = 0; + }; + void applyToAll(ApplyFunctor* func); + + LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor = FALSE); + LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); + + std::string getString(const std::string& name); + std::string getText(const std::string& name); + BOOL getBOOL(const std::string& name); + S32 getS32(const std::string& name); + F32 getF32(const std::string& name); + U32 getU32(const std::string& name); + + LLWString getWString(const std::string& name); + LLVector3 getVector3(const std::string& name); + LLVector3d getVector3d(const std::string& name); + LLRect getRect(const std::string& name); + LLSD getLLSD(const std::string& name); + LLQuaternion getQuaternion(const std::string& name); + + LLColor4 getColor(const std::string& name); + LLColor4 getColor4(const std::string& name); + LLColor3 getColor3(const std::string& name); + + LLSD asLLSD(bool diffs_only); + + // generic getter + template T get(const std::string& name) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - LLControlVariable* control = getControl(name); - LLSD value; - eControlType type = TYPE_COUNT; - - if (control) - { - value = control->get(); - type = control->type(); - } - else - { - LL_WARNS() << "Control " << name << " not found." << LL_ENDL; - return T(); - } - return convert_from_llsd(value, type, name); - } - - void setBOOL(const std::string& name, BOOL val); - void setS32(const std::string& name, S32 val); - void setF32(const std::string& name, F32 val); - void setU32(const std::string& name, U32 val); - void setString(const std::string& name, const std::string& val); - void setVector3(const std::string& name, const LLVector3 &val); - void setVector3d(const std::string& name, const LLVector3d &val); - void setQuaternion(const std::string& name, const LLQuaternion &val); - void setRect(const std::string& name, const LLRect &val); - void setColor4(const std::string& name, const LLColor4 &val); - void setLLSD(const std::string& name, const LLSD& val); - - // type agnostic setter that takes LLSD - void setUntypedValue(const std::string& name, const LLSD& val, bool saved_value = true); - - // generic setter - template void set(const std::string& name, const T& val) - { - LLControlVariable* control = getControl(name); - - if (control && control->isType(get_control_type())) - { - control->set(convert_to_llsd(val)); - } - else - { - LL_WARNS() << "Invalid control " << name << LL_ENDL; - } - } - - BOOL controlExists(const std::string& name); - - // Returns number of controls loaded, 0 if failed - // If require_declaration is false, will auto-declare controls it finds - // as the given type. - U32 loadFromFileLegacy(const std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); - U32 saveToFile(const std::string& filename, BOOL nondefault_only); - U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); - void resetToDefaults(); - void incrCount(const std::string& name); - - bool mSettingsProfile; + LLControlVariable* control = getControl(name); + LLSD value; + eControlType type = TYPE_COUNT; + + if (control) + { + value = control->get(); + type = control->type(); + } + else + { + LL_WARNS() << "Control " << name << " not found." << LL_ENDL; + return T(); + } + return convert_from_llsd(value, type, name); + } + + void setBOOL(const std::string& name, BOOL val); + void setS32(const std::string& name, S32 val); + void setF32(const std::string& name, F32 val); + void setU32(const std::string& name, U32 val); + void setString(const std::string& name, const std::string& val); + void setVector3(const std::string& name, const LLVector3 &val); + void setVector3d(const std::string& name, const LLVector3d &val); + void setQuaternion(const std::string& name, const LLQuaternion &val); + void setRect(const std::string& name, const LLRect &val); + void setColor4(const std::string& name, const LLColor4 &val); + void setLLSD(const std::string& name, const LLSD& val); + + // type agnostic setter that takes LLSD + void setUntypedValue(const std::string& name, const LLSD& val, bool saved_value = true); + + // generic setter + template void set(const std::string& name, const T& val) + { + LLControlVariable* control = getControl(name); + + if (control && control->isType(get_control_type())) + { + control->set(convert_to_llsd(val)); + } + else + { + LL_WARNS() << "Invalid control " << name << LL_ENDL; + } + } + + BOOL controlExists(const std::string& name); + + // Returns number of controls loaded, 0 if failed + // If require_declaration is false, will auto-declare controls it finds + // as the given type. + U32 loadFromFileLegacy(const std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); + U32 saveToFile(const std::string& filename, BOOL nondefault_only); + U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); + void resetToDefaults(); + void incrCount(const std::string& name); + + bool mSettingsProfile; }; @@ -319,124 +319,124 @@ template class LLControlCache : public LLRefCount, public LLInstanceTracker, std::string> { public: - // This constructor will declare a control if it doesn't exist in the contol group - LLControlCache(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment) - : LLInstanceTracker, std::string >(name) - { - if(!group.controlExists(name)) - { - if(!declareTypedControl(group, name, default_value, comment)) - { - LL_ERRS() << "The control could not be created!!!" << LL_ENDL; - } - } - - bindToControl(group, name); - } - - LLControlCache(LLControlGroup& group, - const std::string& name) - : LLInstanceTracker, std::string >(name) - { - if(!group.controlExists(name)) - { - LL_ERRS() << "Control named " << name << "not found." << LL_ENDL; - } - - bindToControl(group, name); - } - - ~LLControlCache() - { - } - - const T& getValue() const { return mCachedValue; } - + // This constructor will declare a control if it doesn't exist in the contol group + LLControlCache(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment) + : LLInstanceTracker, std::string >(name) + { + if(!group.controlExists(name)) + { + if(!declareTypedControl(group, name, default_value, comment)) + { + LL_ERRS() << "The control could not be created!!!" << LL_ENDL; + } + } + + bindToControl(group, name); + } + + LLControlCache(LLControlGroup& group, + const std::string& name) + : LLInstanceTracker, std::string >(name) + { + if(!group.controlExists(name)) + { + LL_ERRS() << "Control named " << name << "not found." << LL_ENDL; + } + + bindToControl(group, name); + } + + ~LLControlCache() + { + } + + const T& getValue() const { return mCachedValue; } + private: - void bindToControl(LLControlGroup& group, const std::string& name) - { - LLControlVariablePtr controlp = group.getControl(name); - mType = controlp->type(); - mCachedValue = convert_from_llsd(controlp->get(), mType, name); - - // Add a listener to the controls signal... - // NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last - mConnection = controlp->getSignal()->connect(0, - boost::bind(&LLControlCache::handleValueChange, this, _2) - ); - mType = controlp->type(); - } - bool declareTypedControl(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment) - { - LLSD init_value; - eControlType type = get_control_type(); - init_value = convert_to_llsd(default_value); - if(type < TYPE_COUNT) - { - group.declareControl(name, type, init_value, comment, LLControlVariable::PERSIST_NO); - return true; - } - return false; - } - - bool handleValueChange(const LLSD& newvalue) - { - mCachedValue = convert_from_llsd(newvalue, mType, ""); - return true; - } + void bindToControl(LLControlGroup& group, const std::string& name) + { + LLControlVariablePtr controlp = group.getControl(name); + mType = controlp->type(); + mCachedValue = convert_from_llsd(controlp->get(), mType, name); + + // Add a listener to the controls signal... + // NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last + mConnection = controlp->getSignal()->connect(0, + boost::bind(&LLControlCache::handleValueChange, this, _2) + ); + mType = controlp->type(); + } + bool declareTypedControl(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment) + { + LLSD init_value; + eControlType type = get_control_type(); + init_value = convert_to_llsd(default_value); + if(type < TYPE_COUNT) + { + group.declareControl(name, type, init_value, comment, LLControlVariable::PERSIST_NO); + return true; + } + return false; + } + + bool handleValueChange(const LLSD& newvalue) + { + mCachedValue = convert_from_llsd(newvalue, mType, ""); + return true; + } private: - T mCachedValue; - eControlType mType; - boost::signals2::scoped_connection mConnection; + T mCachedValue; + eControlType mType; + boost::signals2::scoped_connection mConnection; }; template class LLCachedControl { public: - LLCachedControl(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment = "Declared In Code") - { - mCachedControlPtr = LLControlCache::getInstance(name).get(); - if (! mCachedControlPtr) - { - mCachedControlPtr = new LLControlCache(group, name, default_value, comment); - } - } - - LLCachedControl(LLControlGroup& group, - const std::string& name) - { - mCachedControlPtr = LLControlCache::getInstance(name).get(); - if (! mCachedControlPtr) - { - mCachedControlPtr = new LLControlCache(group, name); - } - } - - operator const T&() const { return mCachedControlPtr->getValue(); } - operator boost::function () const { return boost::function(*this); } - const T& operator()() { return mCachedControlPtr->getValue(); } + LLCachedControl(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment = "Declared In Code") + { + mCachedControlPtr = LLControlCache::getInstance(name).get(); + if (! mCachedControlPtr) + { + mCachedControlPtr = new LLControlCache(group, name, default_value, comment); + } + } + + LLCachedControl(LLControlGroup& group, + const std::string& name) + { + mCachedControlPtr = LLControlCache::getInstance(name).get(); + if (! mCachedControlPtr) + { + mCachedControlPtr = new LLControlCache(group, name); + } + } + + operator const T&() const { return mCachedControlPtr->getValue(); } + operator boost::function () const { return boost::function(*this); } + const T& operator()() { return mCachedControlPtr->getValue(); } private: - LLPointer > mCachedControlPtr; + LLPointer > mCachedControlPtr; }; template <> eControlType get_control_type(); template <> eControlType get_control_type(); template <> eControlType get_control_type(); -template <> eControlType get_control_type(); +template <> eControlType get_control_type(); // Yay BOOL, its really an S32. -//template <> eControlType get_control_type () +//template <> eControlType get_control_type () template <> eControlType get_control_type(); template <> eControlType get_control_type(); template <> eControlType get_control_type(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index dccd63af38..34a50e1fa7 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1,29 +1,29 @@ -/** +/** * @file llappearancemgr.cpp * @brief Manager for initiating appearance changes on the viewer * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #include "llviewerprecompiledheaders.h" #include @@ -71,7 +71,7 @@ #pragma warning (disable:4702) #endif -namespace +namespace { const S32 BAKE_RETRY_MAX_COUNT = 5; const F32 BAKE_RETRY_TIMEOUT = 2.0F; @@ -87,8 +87,8 @@ void doAppearanceCb(LLPointer cb, LLUUID id) std::string self_av_string() { - // On logout gAgentAvatarp can already be invalid - return isAgentAvatarValid() ? gAgentAvatarp->avString() : ""; + // On logout gAgentAvatarp can already be invalid + return isAgentAvatarValid() ? gAgentAvatarp->avString() : ""; } // RAII thingy to guarantee that a variable gets reset when the Setter @@ -97,17 +97,17 @@ std::string self_av_string() class BoolSetter { public: - BoolSetter(bool& var): - mVar(var) - { - mVar = true; - } - ~BoolSetter() - { - mVar = false; - } + BoolSetter(bool& var): + mVar(var) + { + mVar = true; + } + ~BoolSetter() + { + mVar = false; + } private: - bool& mVar; + bool& mVar; }; char ORDER_NUMBER_SEPARATOR('@'); @@ -115,47 +115,47 @@ char ORDER_NUMBER_SEPARATOR('@'); class LLOutfitUnLockTimer: public LLEventTimer { public: - LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) - { - // restart timer on BOF changed event - LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); }); - stop(); - } - - bool tick() override - { - LLAppearanceMgr::instance().setOutfitLocked(false); - return false; - } -// void reset() { mEventTimer.reset(); } - bool getStarted() { return isRunning(); } - -// LLTimer& getEventTimer() { return mEventTimer;} + LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) + { + // restart timer on BOF changed event + LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); }); + stop(); + } + + bool tick() override + { + LLAppearanceMgr::instance().setOutfitLocked(false); + return false; + } +// void reset() { mEventTimer.reset(); } + bool getStarted() { return isRunning(); } + +// LLTimer& getEventTimer() { return mEventTimer;} }; // support for secondlife:///app/appearance SLapps class LLAppearanceHandler : public LLCommandHandler { public: - // requests will be throttled from a non-trusted browser - LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} + // requests will be throttled from a non-trusted browser + LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) - { - // support secondlife:///app/appearance/show, but for now we just - // make all secondlife:///app/appearance SLapps behave this way - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAppearance")) - { - LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); - return true; - } + { + // support secondlife:///app/appearance/show, but for now we just + // make all secondlife:///app/appearance SLapps behave this way + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAppearance")) + { + LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); + return true; + } }; LLAppearanceHandler gAppearanceHandler; @@ -163,27 +163,27 @@ LLAppearanceHandler gAppearanceHandler; LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(name); - gInventory.collectDescendentsIf(parent_id, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - if (0 == cat_array.size()) - return LLUUID(); - else - { - LLViewerInventoryCategory *cat = cat_array.at(0); - if (cat) - return cat->getUUID(); - else - { - LL_WARNS() << "null cat" << LL_ENDL; - return LLUUID(); - } - } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLNameCategoryCollector has_name(name); + gInventory.collectDescendentsIf(parent_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + if (0 == cat_array.size()) + return LLUUID(); + else + { + LLViewerInventoryCategory *cat = cat_array.at(0); + if (cat) + return cat->getUUID(); + else + { + LL_WARNS() << "null cat" << LL_ENDL; + return LLUUID(); + } + } } // We want this to be much lower (e.g. 15.0 is usually fine), bumping @@ -196,261 +196,261 @@ const F32 DEFAULT_RETRY_AFTER_INTERVAL = 300.0; // leave at 0 if the operations become actually reliable). const S32 DEFAULT_MAX_RETRIES = 0; -class LLCallAfterInventoryBatchMgr: public LLEventTimer +class LLCallAfterInventoryBatchMgr: public LLEventTimer { public: - LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - mDstCatID(dst_cat_id), - mTrackingPhase(phase_name), - mOnCompletionFunc(on_completion_func), - mOnFailureFunc(on_failure_func), - mRetryAfter(retry_after), - mMaxRetries(max_retries), - mPendingRequests(0), - mFailCount(0), - mCompletionOrFailureCalled(false), - mRetryCount(0), - LLEventTimer(5.0) - { - if (!mTrackingPhase.empty()) - { - selfStartPhase(mTrackingPhase); - } - } - - void addItems(LLInventoryModel::item_array_t& src_items) - { - for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin(); - it != src_items.end(); - ++it) - { - LLViewerInventoryItem* item = *it; - llassert(item); - addItem(item->getUUID()); - } - } - - // Request or re-request operation for specified item. - void addItem(const LLUUID& item_id) - { - LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; - if (!requestOperation(item_id)) - { - LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; - return; - } - - mPendingRequests++; - // On a re-request, this will reset the timer. - mWaitTimes[item_id] = LLTimer(); - if (mRetryCounts.find(item_id) == mRetryCounts.end()) - { - mRetryCounts[item_id] = 0; - } - else - { - mRetryCounts[item_id]++; - } - } - - virtual bool requestOperation(const LLUUID& item_id) = 0; - - void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp) - { - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) - { - LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; - doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), - mRetryAfter); - return; - } - mPendingRequests--; - F32 elapsed = timestamp.getElapsedTimeF32(); - LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL; - if (mWaitTimes.find(src_id) == mWaitTimes.end()) - { - // No longer waiting for this item - either serviced - // already or gave up after too many retries. - LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id - << " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL; - } - mTimeStats.push(elapsed); - mWaitTimes.erase(src_id); - if (mWaitTimes.empty() && !mCompletionOrFailureCalled) - { - onCompletionOrFailure(); - } - } - - void onCompletionOrFailure() - { - assert (!mCompletionOrFailureCalled); - mCompletionOrFailureCalled = true; - - // Will never call onCompletion() if any item has been flagged as - // a failure - otherwise could wind up with corrupted - // outfit, involuntary nudity, etc. - reportStats(); - if (!mTrackingPhase.empty()) - { - selfStopPhase(mTrackingPhase); - } - if (!mFailCount) - { - onCompletion(); - } - else - { - onFailure(); - } - } - - void onFailure() - { - LL_INFOS() << "failed" << LL_ENDL; - mOnFailureFunc(); - } - - void onCompletion() - { - LL_INFOS() << "done" << LL_ENDL; - mOnCompletionFunc(); - } - - // virtual - // Will be deleted after returning true - only safe to do this if all callbacks have fired. - bool tick() override - { - // mPendingRequests will be zero if all requests have been - // responded to. mWaitTimes.empty() will be true if we have - // received at least one reply for each UUID. If requests - // have been dropped and retried, these will not necessarily - // be the same. Only safe to return true if all requests have - // been serviced, since it will result in this object being - // deleted. - bool all_done = (mPendingRequests==0); - - if (!mWaitTimes.empty()) - { - LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; - for (std::map::iterator it = mWaitTimes.begin(); - it != mWaitTimes.end();) - { - // Use a copy of iterator because it may be erased/invalidated. - std::map::iterator curr_it = it; - ++it; - - F32 time_waited = curr_it->second.getElapsedTimeF32(); - S32 retries = mRetryCounts[curr_it->first]; - if (time_waited > mRetryAfter) - { - if (retries < mMaxRetries) - { - LL_DEBUGS("Avatar") << "Waited " << time_waited << - " for " << curr_it->first << ", retrying" << LL_ENDL; - mRetryCount++; - addItem(curr_it->first); - } - else - { - LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; - mWaitTimes.erase(curr_it); - mFailCount++; - } - } - if (mWaitTimes.empty()) - { - onCompletionOrFailure(); - } - - } - } - return all_done; - } - - void reportStats() - { - LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL; - LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL; - LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL; - LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; - LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; - } - - virtual ~LLCallAfterInventoryBatchMgr() - { - LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; - } + LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id, + const std::string& phase_name, + nullary_func_t on_completion_func, + nullary_func_t on_failure_func = no_op, + F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, + S32 max_retries = DEFAULT_MAX_RETRIES + ): + mDstCatID(dst_cat_id), + mTrackingPhase(phase_name), + mOnCompletionFunc(on_completion_func), + mOnFailureFunc(on_failure_func), + mRetryAfter(retry_after), + mMaxRetries(max_retries), + mPendingRequests(0), + mFailCount(0), + mCompletionOrFailureCalled(false), + mRetryCount(0), + LLEventTimer(5.0) + { + if (!mTrackingPhase.empty()) + { + selfStartPhase(mTrackingPhase); + } + } + + void addItems(LLInventoryModel::item_array_t& src_items) + { + for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin(); + it != src_items.end(); + ++it) + { + LLViewerInventoryItem* item = *it; + llassert(item); + addItem(item->getUUID()); + } + } + + // Request or re-request operation for specified item. + void addItem(const LLUUID& item_id) + { + LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; + if (!requestOperation(item_id)) + { + LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; + return; + } + + mPendingRequests++; + // On a re-request, this will reset the timer. + mWaitTimes[item_id] = LLTimer(); + if (mRetryCounts.find(item_id) == mRetryCounts.end()) + { + mRetryCounts[item_id] = 0; + } + else + { + mRetryCounts[item_id]++; + } + } + + virtual bool requestOperation(const LLUUID& item_id) = 0; + + void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp) + { + if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) + { + LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; + doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), + mRetryAfter); + return; + } + mPendingRequests--; + F32 elapsed = timestamp.getElapsedTimeF32(); + LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL; + if (mWaitTimes.find(src_id) == mWaitTimes.end()) + { + // No longer waiting for this item - either serviced + // already or gave up after too many retries. + LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id + << " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL; + } + mTimeStats.push(elapsed); + mWaitTimes.erase(src_id); + if (mWaitTimes.empty() && !mCompletionOrFailureCalled) + { + onCompletionOrFailure(); + } + } + + void onCompletionOrFailure() + { + assert (!mCompletionOrFailureCalled); + mCompletionOrFailureCalled = true; + + // Will never call onCompletion() if any item has been flagged as + // a failure - otherwise could wind up with corrupted + // outfit, involuntary nudity, etc. + reportStats(); + if (!mTrackingPhase.empty()) + { + selfStopPhase(mTrackingPhase); + } + if (!mFailCount) + { + onCompletion(); + } + else + { + onFailure(); + } + } + + void onFailure() + { + LL_INFOS() << "failed" << LL_ENDL; + mOnFailureFunc(); + } + + void onCompletion() + { + LL_INFOS() << "done" << LL_ENDL; + mOnCompletionFunc(); + } + + // virtual + // Will be deleted after returning true - only safe to do this if all callbacks have fired. + bool tick() override + { + // mPendingRequests will be zero if all requests have been + // responded to. mWaitTimes.empty() will be true if we have + // received at least one reply for each UUID. If requests + // have been dropped and retried, these will not necessarily + // be the same. Only safe to return true if all requests have + // been serviced, since it will result in this object being + // deleted. + bool all_done = (mPendingRequests==0); + + if (!mWaitTimes.empty()) + { + LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; + for (std::map::iterator it = mWaitTimes.begin(); + it != mWaitTimes.end();) + { + // Use a copy of iterator because it may be erased/invalidated. + std::map::iterator curr_it = it; + ++it; + + F32 time_waited = curr_it->second.getElapsedTimeF32(); + S32 retries = mRetryCounts[curr_it->first]; + if (time_waited > mRetryAfter) + { + if (retries < mMaxRetries) + { + LL_DEBUGS("Avatar") << "Waited " << time_waited << + " for " << curr_it->first << ", retrying" << LL_ENDL; + mRetryCount++; + addItem(curr_it->first); + } + else + { + LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; + mWaitTimes.erase(curr_it); + mFailCount++; + } + } + if (mWaitTimes.empty()) + { + onCompletionOrFailure(); + } + + } + } + return all_done; + } + + void reportStats() + { + LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL; + LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL; + LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL; + LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; + LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; + } + + virtual ~LLCallAfterInventoryBatchMgr() + { + LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; + } protected: - std::string mTrackingPhase; - std::map mWaitTimes; - std::map mRetryCounts; - LLUUID mDstCatID; - nullary_func_t mOnCompletionFunc; - nullary_func_t mOnFailureFunc; - F32 mRetryAfter; - S32 mMaxRetries; - S32 mPendingRequests; - S32 mFailCount; - S32 mRetryCount; - bool mCompletionOrFailureCalled; - LLViewerStats::StatsAccumulator mTimeStats; + std::string mTrackingPhase; + std::map mWaitTimes; + std::map mRetryCounts; + LLUUID mDstCatID; + nullary_func_t mOnCompletionFunc; + nullary_func_t mOnFailureFunc; + F32 mRetryAfter; + S32 mMaxRetries; + S32 mPendingRequests; + S32 mFailCount; + S32 mRetryCount; + bool mCompletionOrFailureCalled; + LLViewerStats::StatsAccumulator mTimeStats; }; class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr { public: - LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items, - const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) - { - addItems(src_items); - sInstanceCount++; - } - - ~LLCallAfterInventoryCopyMgr() - { - sInstanceCount--; - } - - virtual bool requestOperation(const LLUUID& item_id) - { - LLViewerInventoryItem *item = gInventory.getItem(item_id); - llassert(item); - LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; - return true; - } - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - mDstCatID, - std::string(), - new LLBoostFuncInventoryCallback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())) - ); - return true; - } - - static S32 getInstanceCount() { return sInstanceCount; } - + LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items, + const LLUUID& dst_cat_id, + const std::string& phase_name, + nullary_func_t on_completion_func, + nullary_func_t on_failure_func = no_op, + F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, + S32 max_retries = DEFAULT_MAX_RETRIES + ): + LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) + { + addItems(src_items); + sInstanceCount++; + } + + ~LLCallAfterInventoryCopyMgr() + { + sInstanceCount--; + } + + virtual bool requestOperation(const LLUUID& item_id) + { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + llassert(item); + LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; + if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) + { + LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; + return true; + } + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + mDstCatID, + std::string(), + new LLBoostFuncInventoryCallback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())) + ); + return true; + } + + static S32 getInstanceCount() { return sInstanceCount; } + private: - static S32 sInstanceCount; + static S32 sInstanceCount; }; S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; @@ -458,97 +458,97 @@ S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; class LLWearCategoryAfterCopy: public LLInventoryCallback { public: - LLWearCategoryAfterCopy(bool append): - mAppend(append) - {} - - // virtual - void fire(const LLUUID& id) - { - // Wear the inventory category. - LLInventoryCategory* cat = gInventory.getCategory(id); - LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); - } + LLWearCategoryAfterCopy(bool append): + mAppend(append) + {} + + // virtual + void fire(const LLUUID& id) + { + // Wear the inventory category. + LLInventoryCategory* cat = gInventory.getCategory(id); + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); + } private: - bool mAppend; + bool mAppend; }; class LLTrackPhaseWrapper : public LLInventoryCallback { public: - LLTrackPhaseWrapper(const std::string& phase_name, LLPointer cb = NULL): - mTrackingPhase(phase_name), - mCB(cb) - { - selfStartPhase(mTrackingPhase); - } - - // virtual - void fire(const LLUUID& id) - { - if (mCB) - { - mCB->fire(id); - } - } - - // virtual - ~LLTrackPhaseWrapper() - { - selfStopPhase(mTrackingPhase); - } + LLTrackPhaseWrapper(const std::string& phase_name, LLPointer cb = NULL): + mTrackingPhase(phase_name), + mCB(cb) + { + selfStartPhase(mTrackingPhase); + } + + // virtual + void fire(const LLUUID& id) + { + if (mCB) + { + mCB->fire(id); + } + } + + // virtual + ~LLTrackPhaseWrapper() + { + selfStopPhase(mTrackingPhase); + } protected: - std::string mTrackingPhase; - LLPointer mCB; + std::string mTrackingPhase; + LLPointer mCB; }; LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, - bool enforce_ordering, - nullary_func_t post_update_func - ): - mFireCount(0), - mEnforceItemRestrictions(enforce_item_restrictions), - mEnforceOrdering(enforce_ordering), - mPostUpdateFunc(post_update_func) + bool enforce_ordering, + nullary_func_t post_update_func + ): + mFireCount(0), + mEnforceItemRestrictions(enforce_item_restrictions), + mEnforceOrdering(enforce_ordering), + mPostUpdateFunc(post_update_func) { - selfStartPhase("update_appearance_on_destroy"); + selfStartPhase("update_appearance_on_destroy"); } void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); - const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); + const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; #ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; #endif - mFireCount++; + mFireCount++; } LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { - if (!LLApp::isExiting()) - { - // speculative fix for MAINT-1150 - LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; + if (!LLApp::isExiting()) + { + // speculative fix for MAINT-1150 + LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; - selfStopPhase("update_appearance_on_destroy"); + selfStopPhase("update_appearance_on_destroy"); - LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, - mEnforceOrdering, - mPostUpdateFunc); - } + LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, + mEnforceOrdering, + mPostUpdateFunc); + } } LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): - mItemID(item_id) + mItemID(item_id) { } LLRequestServerAppearanceUpdateOnDestroy::~LLRequestServerAppearanceUpdateOnDestroy() { - LL_DEBUGS("Avatar") << "ATT requesting server appearance update" << LL_ENDL; + LL_DEBUGS("Avatar") << "ATT requesting server appearance update" << LL_ENDL; if (!LLApp::isExiting()) { LLAppearanceMgr::instance().requestServerAppearanceUpdate(); @@ -557,30 +557,30 @@ LLRequestServerAppearanceUpdateOnDestroy::~LLRequestServerAppearanceUpdateOnDest void edit_wearable_and_customize_avatar(LLUUID item_id) { - // Start editing the item if previously requested. - gAgentWearables.editWearableIfRequested(item_id); - - // TODO: camera mode may not be changed if a debug setting is tweaked - if( gAgentCamera.cameraCustomizeAvatar() ) - { - // If we're in appearance editing mode, the current tab may need to be refreshed - LLSidepanelAppearance *panel = dynamic_cast( - LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel) - { - panel->showDefaultSubpart(); - } - } + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(item_id); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( gAgentCamera.cameraCustomizeAvatar() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + LLSidepanelAppearance *panel = dynamic_cast( + LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel) + { + panel->showDefaultSubpart(); + } + } } LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() { - if (!LLApp::isExiting()) - { - LLAppearanceMgr::instance().updateAppearanceFromCOF( - true,true, - boost::bind(edit_wearable_and_customize_avatar, mItemID)); - } + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().updateAppearanceFromCOF( + true,true, + boost::bind(edit_wearable_and_customize_avatar, mItemID)); + } } class LLBrokenLinkObserver : public LLInventoryObserver @@ -651,738 +651,738 @@ void LLBrokenLinkObserver::postProcess() struct LLFoundData { - LLFoundData() : - mAssetType(LLAssetType::AT_NONE), - mWearableType(LLWearableType::WT_INVALID), - mWearable(NULL) {} - - LLFoundData(const LLUUID& item_id, - const LLUUID& asset_id, - const std::string& name, - const LLAssetType::EType& asset_type, - const LLWearableType::EType& wearable_type, - const bool is_replacement = false - ) : - mItemID(item_id), - mAssetID(asset_id), - mName(name), - mAssetType(asset_type), - mWearableType(wearable_type), - mIsReplacement(is_replacement), - mWearable( NULL ) {} - - LLUUID mItemID; - LLUUID mAssetID; - std::string mName; - LLAssetType::EType mAssetType; - LLWearableType::EType mWearableType; - LLViewerWearable* mWearable; - bool mIsReplacement; + LLFoundData() : + mAssetType(LLAssetType::AT_NONE), + mWearableType(LLWearableType::WT_INVALID), + mWearable(NULL) {} + + LLFoundData(const LLUUID& item_id, + const LLUUID& asset_id, + const std::string& name, + const LLAssetType::EType& asset_type, + const LLWearableType::EType& wearable_type, + const bool is_replacement = false + ) : + mItemID(item_id), + mAssetID(asset_id), + mName(name), + mAssetType(asset_type), + mWearableType(wearable_type), + mIsReplacement(is_replacement), + mWearable( NULL ) {} + + LLUUID mItemID; + LLUUID mAssetID; + std::string mName; + LLAssetType::EType mAssetType; + LLWearableType::EType mWearableType; + LLViewerWearable* mWearable; + bool mIsReplacement; }; - + class LLWearableHoldingPattern { - LOG_CLASS(LLWearableHoldingPattern); + LOG_CLASS(LLWearableHoldingPattern); public: - LLWearableHoldingPattern(); - ~LLWearableHoldingPattern(); - - bool pollFetchCompletion(); - void onFetchCompletion(); - bool isFetchCompleted(); - bool isTimedOut(); - - void checkMissingWearables(); - bool pollMissingWearables(); - bool isMissingCompleted(); - void recoverMissingWearable(LLWearableType::EType type); - void clearCOFLinksForMissingWearables(); - - void onWearableAssetFetch(LLViewerWearable *wearable); - void onAllComplete(); - - typedef std::list found_list_t; - found_list_t& getFoundList(); - void eraseTypeToLink(LLWearableType::EType type); - void eraseTypeToRecover(LLWearableType::EType type); - void setObjItems(const LLInventoryModel::item_array_t& items); - void setGestItems(const LLInventoryModel::item_array_t& items); - bool isMostRecent(); - void handleLateArrivals(); - void resetTime(F32 timeout); - static S32 countActive() { return sActiveHoldingPatterns.size(); } - S32 index() { return mIndex; } - + LLWearableHoldingPattern(); + ~LLWearableHoldingPattern(); + + bool pollFetchCompletion(); + void onFetchCompletion(); + bool isFetchCompleted(); + bool isTimedOut(); + + void checkMissingWearables(); + bool pollMissingWearables(); + bool isMissingCompleted(); + void recoverMissingWearable(LLWearableType::EType type); + void clearCOFLinksForMissingWearables(); + + void onWearableAssetFetch(LLViewerWearable *wearable); + void onAllComplete(); + + typedef std::list found_list_t; + found_list_t& getFoundList(); + void eraseTypeToLink(LLWearableType::EType type); + void eraseTypeToRecover(LLWearableType::EType type); + void setObjItems(const LLInventoryModel::item_array_t& items); + void setGestItems(const LLInventoryModel::item_array_t& items); + bool isMostRecent(); + void handleLateArrivals(); + void resetTime(F32 timeout); + static S32 countActive() { return sActiveHoldingPatterns.size(); } + S32 index() { return mIndex; } + private: - found_list_t mFoundList; - LLInventoryModel::item_array_t mObjItems; - LLInventoryModel::item_array_t mGestItems; - typedef std::set type_set_t; - type_set_t mTypesToRecover; - type_set_t mTypesToLink; - S32 mResolved; - LLTimer mWaitTime; - bool mFired; - typedef std::set type_set_hp; - static type_set_hp sActiveHoldingPatterns; - static S32 sNextIndex; - S32 mIndex; - bool mIsMostRecent; - std::set mLateArrivals; - bool mIsAllComplete; + found_list_t mFoundList; + LLInventoryModel::item_array_t mObjItems; + LLInventoryModel::item_array_t mGestItems; + typedef std::set type_set_t; + type_set_t mTypesToRecover; + type_set_t mTypesToLink; + S32 mResolved; + LLTimer mWaitTime; + bool mFired; + typedef std::set type_set_hp; + static type_set_hp sActiveHoldingPatterns; + static S32 sNextIndex; + S32 mIndex; + bool mIsMostRecent; + std::set mLateArrivals; + bool mIsAllComplete; }; LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; S32 LLWearableHoldingPattern::sNextIndex = 0; LLWearableHoldingPattern::LLWearableHoldingPattern(): - mResolved(0), - mFired(false), - mIsMostRecent(true), - mIsAllComplete(false) -{ - if (countActive()>0) - { - LL_INFOS() << "Creating LLWearableHoldingPattern when " - << countActive() - << " other attempts are active." - << " Flagging others as invalid." - << LL_ENDL; - for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); - it != sActiveHoldingPatterns.end(); - ++it) - { - (*it)->mIsMostRecent = false; - } - - } - mIndex = sNextIndex++; - sActiveHoldingPatterns.insert(this); - LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; - selfStartPhase("holding_pattern"); + mResolved(0), + mFired(false), + mIsMostRecent(true), + mIsAllComplete(false) +{ + if (countActive()>0) + { + LL_INFOS() << "Creating LLWearableHoldingPattern when " + << countActive() + << " other attempts are active." + << " Flagging others as invalid." + << LL_ENDL; + for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); + it != sActiveHoldingPatterns.end(); + ++it) + { + (*it)->mIsMostRecent = false; + } + + } + mIndex = sNextIndex++; + sActiveHoldingPatterns.insert(this); + LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; + selfStartPhase("holding_pattern"); } LLWearableHoldingPattern::~LLWearableHoldingPattern() { - sActiveHoldingPatterns.erase(this); - if (isMostRecent()) - { - selfStopPhase("holding_pattern"); - } - LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; + sActiveHoldingPatterns.erase(this); + if (isMostRecent()) + { + selfStopPhase("holding_pattern"); + } + LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; } bool LLWearableHoldingPattern::isMostRecent() { - return mIsMostRecent; + return mIsMostRecent; } LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList() { - return mFoundList; + return mFoundList; } void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type) { - mTypesToLink.erase(type); + mTypesToLink.erase(type); } void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type) { - mTypesToRecover.erase(type); + mTypesToRecover.erase(type); } void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) { - mObjItems = items; + mObjItems = items; } void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items) { - mGestItems = items; + mGestItems = items; } bool LLWearableHoldingPattern::isFetchCompleted() { - return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? + return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? } bool LLWearableHoldingPattern::isTimedOut() { - return mWaitTime.hasExpired(); + return mWaitTime.hasExpired(); } void LLWearableHoldingPattern::checkMissingWearables() { - if (!isMostRecent()) - { - // runway why don't we actually skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - std::vector found_by_type(LLWearableType::WT_COUNT,0); - std::vector requested_by_type(LLWearableType::WT_COUNT,0); - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) - { - LLFoundData &data = *it; - if (data.mWearableType < LLWearableType::WT_COUNT) - requested_by_type[data.mWearableType]++; - if (data.mWearable) - found_by_type[data.mWearableType]++; - } - - for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) - { - if (requested_by_type[type] > found_by_type[type]) - { - LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL; - } - if (found_by_type[type] > 0) - continue; - if ( - // If at least one wearable of certain types (pants/shirt/skirt) - // was requested but none was found, create a default asset as a replacement. - // In all other cases, don't do anything. - // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud - // due to logic in LLVOAvatarSelf::getIsCloud(). - // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. - (requested_by_type[type] > 0) && - ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) - { - mTypesToRecover.insert(type); - mTypesToLink.insert(type); - recoverMissingWearable((LLWearableType::EType)type); - LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL; - } - } - - resetTime(60.0F); - - if (isMostRecent()) - { - selfStartPhase("get_missing_wearables_2"); - } - if (!pollMissingWearables()) - { - doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); - } + if (!isMostRecent()) + { + // runway why don't we actually skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + std::vector found_by_type(LLWearableType::WT_COUNT,0); + std::vector requested_by_type(LLWearableType::WT_COUNT,0); + for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + { + LLFoundData &data = *it; + if (data.mWearableType < LLWearableType::WT_COUNT) + requested_by_type[data.mWearableType]++; + if (data.mWearable) + found_by_type[data.mWearableType]++; + } + + for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) + { + if (requested_by_type[type] > found_by_type[type]) + { + LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL; + } + if (found_by_type[type] > 0) + continue; + if ( + // If at least one wearable of certain types (pants/shirt/skirt) + // was requested but none was found, create a default asset as a replacement. + // In all other cases, don't do anything. + // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud + // due to logic in LLVOAvatarSelf::getIsCloud(). + // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. + (requested_by_type[type] > 0) && + ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) + { + mTypesToRecover.insert(type); + mTypesToLink.insert(type); + recoverMissingWearable((LLWearableType::EType)type); + LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL; + } + } + + resetTime(60.0F); + + if (isMostRecent()) + { + selfStartPhase("get_missing_wearables_2"); + } + if (!pollMissingWearables()) + { + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); + } } void LLWearableHoldingPattern::onAllComplete() { - if (isAgentAvatarValid()) - { - gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); - } - - if (!isMostRecent()) - { - // runway need to skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - // Activate all gestures in this folder - if (mGestItems.size() > 0) - { - LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL; - - LLGestureMgr::instance().activateGestures(mGestItems); - - // Update the inventory item labels to reflect the fact - // they are active. - LLViewerInventoryCategory* catp = - gInventory.getCategory(LLAppearanceMgr::instance().getCOF()); - - if (catp) - { - gInventory.updateCategory(catp); - gInventory.notifyObservers(); - } - } - - if (isAgentAvatarValid()) - { - LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; - LLAgentWearables::llvo_vec_t objects_to_remove; - LLAgentWearables::llvo_vec_t objects_to_retain; - LLInventoryModel::item_array_t items_to_add; - - LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, - objects_to_remove, - objects_to_retain, - items_to_add); - - LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() - << " attachments" << LL_ENDL; - - // Here we remove the attachment pos overrides for *all* - // attachments, even those that are not being removed. This is - // needed to get joint positions all slammed down to their - // pre-attachment states. - gAgentAvatarp->clearAttachmentOverrides(); - - if (objects_to_remove.size() || items_to_add.size()) - { - LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() - << " and add " << items_to_add.size() << " items" << LL_ENDL; - } - - // Take off the attachments that will no longer be in the outfit. - LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); - - // Update wearables. - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " - << mResolved << " wearable items " << LL_ENDL; - LLAppearanceMgr::instance().updateAgentWearables(this); - - // Restore attachment pos overrides for the attachments that - // are remaining in the outfit. - for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); - it != objects_to_retain.end(); - ++it) - { - LLViewerObject *objectp = *it; + if (isAgentAvatarValid()) + { + gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); + } + + if (!isMostRecent()) + { + // runway need to skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + // Activate all gestures in this folder + if (mGestItems.size() > 0) + { + LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL; + + LLGestureMgr::instance().activateGestures(mGestItems); + + // Update the inventory item labels to reflect the fact + // they are active. + LLViewerInventoryCategory* catp = + gInventory.getCategory(LLAppearanceMgr::instance().getCOF()); + + if (catp) + { + gInventory.updateCategory(catp); + gInventory.notifyObservers(); + } + } + + if (isAgentAvatarValid()) + { + LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; + LLAgentWearables::llvo_vec_t objects_to_remove; + LLAgentWearables::llvo_vec_t objects_to_retain; + LLInventoryModel::item_array_t items_to_add; + + LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, + objects_to_remove, + objects_to_retain, + items_to_add); + + LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() + << " attachments" << LL_ENDL; + + // Here we remove the attachment pos overrides for *all* + // attachments, even those that are not being removed. This is + // needed to get joint positions all slammed down to their + // pre-attachment states. + gAgentAvatarp->clearAttachmentOverrides(); + + if (objects_to_remove.size() || items_to_add.size()) + { + LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() + << " and add " << items_to_add.size() << " items" << LL_ENDL; + } + + // Take off the attachments that will no longer be in the outfit. + LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); + + // Update wearables. + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " + << mResolved << " wearable items " << LL_ENDL; + LLAppearanceMgr::instance().updateAgentWearables(this); + + // Restore attachment pos overrides for the attachments that + // are remaining in the outfit. + for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); + it != objects_to_retain.end(); + ++it) + { + LLViewerObject *objectp = *it; if (!objectp->isAnimatedObject()) { gAgentAvatarp->addAttachmentOverridesForObject(objectp); } - } - - // Add new attachments to match those requested. - LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; - LLAgentWearables::userAttachMultipleAttachments(items_to_add); - } - - if (isFetchCompleted() && isMissingCompleted()) - { - // Only safe to delete if all wearable callbacks and all missing wearables completed. - delete this; - } - else - { - mIsAllComplete = true; - handleLateArrivals(); - } + } + + // Add new attachments to match those requested. + LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; + LLAgentWearables::userAttachMultipleAttachments(items_to_add); + } + + if (isFetchCompleted() && isMissingCompleted()) + { + // Only safe to delete if all wearable callbacks and all missing wearables completed. + delete this; + } + else + { + mIsAllComplete = true; + handleLateArrivals(); + } } void LLWearableHoldingPattern::onFetchCompletion() { - if (isMostRecent()) - { - selfStopPhase("get_wearables_2"); - } - - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + if (isMostRecent()) + { + selfStopPhase("get_wearables_2"); + } + + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } - checkMissingWearables(); + checkMissingWearables(); } // Runs as an idle callback until all wearables are fetched (or we time out). bool LLWearableHoldingPattern::pollFetchCompletion() { - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + bool completed = isFetchCompleted(); + bool timed_out = isTimedOut(); + bool done = completed || timed_out; - bool completed = isFetchCompleted(); - bool timed_out = isTimedOut(); - bool done = completed || timed_out; + if (done) + { + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; - if (done) - { - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; + mFired = true; - mFired = true; - - if (timed_out) - { - LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL; - } + if (timed_out) + { + LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL; + } - onFetchCompletion(); - } - return done; + onFetchCompletion(); + } + return done; } void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) { - if (!holder->isMostRecent()) - { - LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - // runway skip here? - } - - LL_INFOS("Avatar") << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; - holder->eraseTypeToLink(type); - // Add wearable to FoundData for actual wearing - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - - if (linked_item) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); - - if (item) - { - LLFoundData found(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, - true // is replacement - ); - found.mWearable = wearable; - holder->getFoundList().push_front(found); - } - else - { - LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; - } - } - else - { - LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; - } + if (!holder->isMostRecent()) + { + LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + // runway skip here? + } + + LL_INFOS("Avatar") << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; + holder->eraseTypeToLink(type); + // Add wearable to FoundData for actual wearing + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + + if (linked_item) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + + if (item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, + true // is replacement + ); + found.mWearable = wearable; + holder->getFoundList().push_front(found); + } + else + { + LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; + } + } + else + { + LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; + } } void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder) { - if (!holder->isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } + if (!holder->isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } - LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; - LLConstPointer itemp = gInventory.getItem(item_id); - wearable->setItemID(item_id); - holder->eraseTypeToRecover(type); - llassert(itemp); - if (itemp) - { - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); + LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; + LLConstPointer itemp = gInventory.getItem(item_id); + wearable->setItemID(item_id); + holder->eraseTypeToRecover(type); + llassert(itemp); + if (itemp) + { + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); - link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); - } + link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); + } } void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type) { - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - // Try to recover by replacing missing wearable with a new one. - LLNotificationsUtil::add("ReplacedMissingWearable"); - LL_DEBUGS("Avatar") << "Wearable of type '" << LLWearableType::getInstance()->getTypeName(type) - << "' could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; - LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - - // Add a new one in the lost and found folder. - const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this)); + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + // Try to recover by replacing missing wearable with a new one. + LLNotificationsUtil::add("ReplacedMissingWearable"); + LL_DEBUGS("Avatar") << "Wearable of type '" << LLWearableType::getInstance()->getTypeName(type) + << "' could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; + LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); + + // Add a new one in the lost and found folder. + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_cb,_1,type,wearable,this)); create_inventory_wearable(gAgent.getID(), - gAgent.getSessionID(), - lost_and_found_id, - wearable->getTransactionID(), - wearable->getName(), - wearable->getDescription(), - wearable->getAssetType(), - wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), - cb); + gAgent.getSessionID(), + lost_and_found_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); } bool LLWearableHoldingPattern::isMissingCompleted() { - return mTypesToLink.size()==0 && mTypesToRecover.size()==0; + return mTypesToLink.size()==0 && mTypesToRecover.size()==0; } void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() { - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) - { - LLFoundData &data = *it; - if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) - { - // Wearable link that was never resolved; remove links to it from COF - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); - } - } + for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + { + LLFoundData &data = *it; + if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) + { + // Wearable link that was never resolved; remove links to it from COF + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; + LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); + } + } } bool LLWearableHoldingPattern::pollMissingWearables() { - if (!isMostRecent()) - { - // runway skip here? - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - bool timed_out = isTimedOut(); - bool missing_completed = isMissingCompleted(); - bool done = timed_out || missing_completed; - - if (!done) - { - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() - << " links " << mTypesToLink.size() - << " wearables, timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() - << " done " << done << LL_ENDL; - } - - if (done) - { - if (isMostRecent()) - { - selfStopPhase("get_missing_wearables_2"); - } - - gAgentAvatarp->debugWearablesLoaded(); - - // BAP - if we don't call clearCOFLinksForMissingWearables() - // here, we won't have to add the link back in later if the - // wearable arrives late. This is to avoid corruption of - // wearable ordering info. Also has the effect of making - // unworn item links visible in the COF under some - // circumstances. - - //clearCOFLinksForMissingWearables(); - onAllComplete(); - } - return done; -} + if (!isMostRecent()) + { + // runway skip here? + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } -// Handle wearables that arrived after the timeout period expired. -void LLWearableHoldingPattern::handleLateArrivals() -{ - // Only safe to run if we have previously finished the missing - // wearables and other processing - otherwise we could be in some - // intermediate state - but have not been superceded by a later - // outfit change request. - if (mLateArrivals.size() == 0) - { - // Nothing to process. - return; - } - if (!isMostRecent()) - { - LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL; - } - if (!mIsAllComplete) - { - LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; - } - - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; - - // Update mFoundList using late-arriving wearables. - std::set replaced_types; - for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - iter != getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - for (std::set::iterator wear_it = mLateArrivals.begin(); - wear_it != mLateArrivals.end(); - ++wear_it) - { - LLViewerWearable *wearable = *wear_it; - - if(wearable->getAssetID() == data.mAssetID) - { - data.mWearable = wearable; - - replaced_types.insert(data.mWearableType); - - // BAP - if we didn't call - // clearCOFLinksForMissingWearables() earlier, we - // don't need to restore the link here. Fixes - // wearable ordering problems. - - // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false); - - // BAP failing this means inventory or asset server - // are corrupted in a way we don't handle. - llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType)); - break; - } - } - } - - // Remove COF links for any default wearables previously used to replace the late arrivals. - // All this pussyfooting around with a while loop and explicit - // iterator incrementing is to allow removing items from the list - // without clobbering the iterator we're using to navigate. - LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - while (iter != getFoundList().end()) - { - LLFoundData& data = *iter; - - // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. - if (data.mWearable && data.mIsReplacement && - replaced_types.find(data.mWearableType) != replaced_types.end()) - { - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); - std::list::iterator clobber_ator = iter; - ++iter; - getFoundList().erase(clobber_ator); - } - else - { - ++iter; - } - } - - // Clear contents of late arrivals. - mLateArrivals.clear(); - - // Update appearance based on mFoundList - LLAppearanceMgr::instance().updateAgentWearables(this); -} + bool timed_out = isTimedOut(); + bool missing_completed = isMissingCompleted(); + bool done = timed_out || missing_completed; -void LLWearableHoldingPattern::resetTime(F32 timeout) -{ - mWaitTime.reset(); - mWaitTime.setTimerExpirySec(timeout); -} + if (!done) + { + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() + << " links " << mTypesToLink.size() + << " wearables, timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() + << " done " << done << LL_ENDL; + } -void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) -{ - if (!isMostRecent()) - { - LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; - } - - mResolved += 1; // just counting callbacks, not successes. - LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; - if (!wearable) - { - LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; - } - - if (mFired) - { - LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL; - if (wearable) - { - mLateArrivals.insert(wearable); - if (mIsAllComplete) - { - handleLateArrivals(); - } - } - return; - } - - if (!wearable) - { - return; - } - - U32 use_count = 0; - for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - iter != getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - if (wearable->getAssetID() == data.mAssetID) - { - // Failing this means inventory or asset server are corrupted in a way we don't handle. - if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) - { - LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL; - break; - } - - if (use_count == 0) - { - data.mWearable = wearable; - use_count++; - } - else - { - LLViewerInventoryItem* wearable_item = gInventory.getItem(data.mItemID); - if (wearable_item && wearable_item->isFinished() && wearable_item->getPermissions().allowModifyBy(gAgentID)) - { - // We can't edit and do some other interactions with same asset twice, copy it - // Note: can't update incomplete items. Usually attached from previous viewer build, but - // consider adding fetch and completion callback - LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(wearable, wearable->getName()); - data.mWearable = new_wearable; - data.mAssetID = new_wearable->getAssetID(); - - // Update existing inventory item - wearable_item->setAssetUUID(new_wearable->getAssetID()); - wearable_item->setTransactionID(new_wearable->getTransactionID()); - gInventory.updateItem(wearable_item, LLInventoryObserver::INTERNAL); - wearable_item->updateServer(FALSE); - - use_count++; - } - else - { - // Note: technically a bug, LLViewerWearable can identify only one item id at a time, - // yet we are tying it to multiple items here. - // LLViewerWearable need to support more then one item. - LL_WARNS() << "Same LLViewerWearable is used by multiple items! " << wearable->getAssetID() << LL_ENDL; - data.mWearable = wearable; - } - } - } - } - - if (use_count > 1) - { - LL_WARNS() << "Copying wearable, multiple asset id uses! " << wearable->getAssetID() << LL_ENDL; - gInventory.notifyObservers(); - } -} + if (done) + { + if (isMostRecent()) + { + selfStopPhase("get_missing_wearables_2"); + } -static void onWearableAssetFetch(LLViewerWearable* wearable, void* data) -{ - LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; - holder->onWearableAssetFetch(wearable); -} + gAgentAvatarp->debugWearablesLoaded(); + + // BAP - if we don't call clearCOFLinksForMissingWearables() + // here, we won't have to add the link back in later if the + // wearable arrives late. This is to avoid corruption of + // wearable ordering info. Also has the effect of making + // unworn item links visible in the COF under some + // circumstances. + + //clearCOFLinksForMissingWearables(); + onAllComplete(); + } + return done; +} + +// Handle wearables that arrived after the timeout period expired. +void LLWearableHoldingPattern::handleLateArrivals() +{ + // Only safe to run if we have previously finished the missing + // wearables and other processing - otherwise we could be in some + // intermediate state - but have not been superceded by a later + // outfit change request. + if (mLateArrivals.size() == 0) + { + // Nothing to process. + return; + } + if (!isMostRecent()) + { + LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL; + } + if (!mIsAllComplete) + { + LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; + } + + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; + + // Update mFoundList using late-arriving wearables. + std::set replaced_types; + for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + iter != getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + for (std::set::iterator wear_it = mLateArrivals.begin(); + wear_it != mLateArrivals.end(); + ++wear_it) + { + LLViewerWearable *wearable = *wear_it; + + if(wearable->getAssetID() == data.mAssetID) + { + data.mWearable = wearable; + + replaced_types.insert(data.mWearableType); + + // BAP - if we didn't call + // clearCOFLinksForMissingWearables() earlier, we + // don't need to restore the link here. Fixes + // wearable ordering problems. + + // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false); + + // BAP failing this means inventory or asset server + // are corrupted in a way we don't handle. + llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType)); + break; + } + } + } + + // Remove COF links for any default wearables previously used to replace the late arrivals. + // All this pussyfooting around with a while loop and explicit + // iterator incrementing is to allow removing items from the list + // without clobbering the iterator we're using to navigate. + LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + while (iter != getFoundList().end()) + { + LLFoundData& data = *iter; + + // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. + if (data.mWearable && data.mIsReplacement && + replaced_types.find(data.mWearableType) != replaced_types.end()) + { + LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); + std::list::iterator clobber_ator = iter; + ++iter; + getFoundList().erase(clobber_ator); + } + else + { + ++iter; + } + } + + // Clear contents of late arrivals. + mLateArrivals.clear(); + + // Update appearance based on mFoundList + LLAppearanceMgr::instance().updateAgentWearables(this); +} + +void LLWearableHoldingPattern::resetTime(F32 timeout) +{ + mWaitTime.reset(); + mWaitTime.setTimerExpirySec(timeout); +} + +void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) +{ + if (!isMostRecent()) + { + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + } + + mResolved += 1; // just counting callbacks, not successes. + LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; + if (!wearable) + { + LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; + } + + if (mFired) + { + LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL; + if (wearable) + { + mLateArrivals.insert(wearable); + if (mIsAllComplete) + { + handleLateArrivals(); + } + } + return; + } + + if (!wearable) + { + return; + } + + U32 use_count = 0; + for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); + iter != getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + if (wearable->getAssetID() == data.mAssetID) + { + // Failing this means inventory or asset server are corrupted in a way we don't handle. + if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) + { + LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL; + break; + } + + if (use_count == 0) + { + data.mWearable = wearable; + use_count++; + } + else + { + LLViewerInventoryItem* wearable_item = gInventory.getItem(data.mItemID); + if (wearable_item && wearable_item->isFinished() && wearable_item->getPermissions().allowModifyBy(gAgentID)) + { + // We can't edit and do some other interactions with same asset twice, copy it + // Note: can't update incomplete items. Usually attached from previous viewer build, but + // consider adding fetch and completion callback + LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(wearable, wearable->getName()); + data.mWearable = new_wearable; + data.mAssetID = new_wearable->getAssetID(); + + // Update existing inventory item + wearable_item->setAssetUUID(new_wearable->getAssetID()); + wearable_item->setTransactionID(new_wearable->getTransactionID()); + gInventory.updateItem(wearable_item, LLInventoryObserver::INTERNAL); + wearable_item->updateServer(FALSE); + + use_count++; + } + else + { + // Note: technically a bug, LLViewerWearable can identify only one item id at a time, + // yet we are tying it to multiple items here. + // LLViewerWearable need to support more then one item. + LL_WARNS() << "Same LLViewerWearable is used by multiple items! " << wearable->getAssetID() << LL_ENDL; + data.mWearable = wearable; + } + } + } + } + + if (use_count > 1) + { + LL_WARNS() << "Copying wearable, multiple asset id uses! " << wearable->getAssetID() << LL_ENDL; + gInventory.notifyObservers(); + } +} + +static void onWearableAssetFetch(LLViewerWearable* wearable, void* data) +{ + LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; + holder->onWearableAssetFetch(wearable); +} static void removeDuplicateItems(LLInventoryModel::item_array_t& items) { - LLInventoryModel::item_array_t new_items; - std::set items_seen; - std::deque tmp_list; - // Traverse from the front and keep the first of each item - // encountered, so we actually keep the *last* of each duplicate - // item. This is needed to give the right priority when adding - // duplicate items to an existing outfit. - for (S32 i=items.size()-1; i>=0; i--) - { - LLViewerInventoryItem *item = items.at(i); - LLUUID item_id = item->getLinkedUUID(); - if (items_seen.find(item_id)!=items_seen.end()) - continue; - items_seen.insert(item_id); - tmp_list.push_front(item); - } - for (std::deque::iterator it = tmp_list.begin(); - it != tmp_list.end(); - ++it) - { - new_items.push_back(*it); - } - items = new_items; + LLInventoryModel::item_array_t new_items; + std::set items_seen; + std::deque tmp_list; + // Traverse from the front and keep the first of each item + // encountered, so we actually keep the *last* of each duplicate + // item. This is needed to give the right priority when adding + // duplicate items to an existing outfit. + for (S32 i=items.size()-1; i>=0; i--) + { + LLViewerInventoryItem *item = items.at(i); + LLUUID item_id = item->getLinkedUUID(); + if (items_seen.find(item_id)!=items_seen.end()) + continue; + items_seen.insert(item_id); + tmp_list.push_front(item); + } + for (std::deque::iterator it = tmp_list.begin(); + it != tmp_list.end(); + ++it) + { + new_items.push_back(*it); + } + items = new_items; } //========================================================================= @@ -1391,98 +1391,98 @@ const std::string LLAppearanceMgr::sExpectedTextureName = "OutfitPreview"; const LLUUID LLAppearanceMgr::getCOF() const { - return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); } S32 LLAppearanceMgr::getCOFVersion() const { - LLViewerInventoryCategory *cof = gInventory.getCategory(getCOF()); - if (cof) - { - return cof->getVersion(); - } - else - { - return LLViewerInventoryCategory::VERSION_UNKNOWN; - } + LLViewerInventoryCategory *cof = gInventory.getCategory(getCOF()); + if (cof) + { + return cof->getVersion(); + } + else + { + return LLViewerInventoryCategory::VERSION_UNKNOWN; + } } const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() { - const LLUUID& current_outfit_cat = getCOF(); - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - // Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't - // return preferred type. - LLIsType is_category( LLAssetType::AT_CATEGORY ); - gInventory.collectDescendentsIf(current_outfit_cat, - cat_array, - item_array, - false, - is_category); - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) - { - const LLViewerInventoryItem *item = (*iter); - const LLViewerInventoryCategory *cat = item->getLinkedCategory(); - if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) - { - const LLUUID parent_id = cat->getParentUUID(); - LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id); - // if base outfit moved to trash it means that we don't have base outfit - if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) - { - return NULL; - } - return item; - } - } - return NULL; + const LLUUID& current_outfit_cat = getCOF(); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + // Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't + // return preferred type. + LLIsType is_category( LLAssetType::AT_CATEGORY ); + gInventory.collectDescendentsIf(current_outfit_cat, + cat_array, + item_array, + false, + is_category); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + const LLViewerInventoryCategory *cat = item->getLinkedCategory(); + if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + const LLUUID parent_id = cat->getParentUUID(); + LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id); + // if base outfit moved to trash it means that we don't have base outfit + if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) + { + return NULL; + } + return item; + } + } + return NULL; } bool LLAppearanceMgr::getBaseOutfitName(std::string& name) { - const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); - if(outfit_link) - { - const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory(); - if (cat) - { - name = cat->getName(); - return true; - } - } - return false; + const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); + if(outfit_link) + { + const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory(); + if (cat) + { + name = cat->getName(); + return true; + } + } + return false; } const LLUUID LLAppearanceMgr::getBaseOutfitUUID() { - const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); - if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; + const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); + if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; - const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); - if (!outfit_cat) return LLUUID::null; + const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); + if (!outfit_cat) return LLUUID::null; - if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) - { - LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL; - return LLUUID::null; - } + if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL; + return LLUUID::null; + } - return outfit_cat->getUUID(); + return outfit_cat->getUUID(); } void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false) { - if (inv_item.isNull()) - return; - - LLViewerInventoryItem *item = gInventory.getItem(inv_item); - if (item) - { - LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, do_replace); - } + if (inv_item.isNull()) + return; + + LLViewerInventoryItem *item = gInventory.getItem(inv_item); + if (item) + { + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, do_replace); + } } void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, @@ -1490,8 +1490,8 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, bool replace, LLPointer cb) { - LL_DEBUGS("UIUsage") << "wearItemsOnAvatar" << LL_ENDL; - LLUIUsage::instance().logCommand("Avatar.WearItem"); + LL_DEBUGS("UIUsage") << "wearItemsOnAvatar" << LL_ENDL; + LLUIUsage::instance().logCommand("Avatar.WearItem"); bool first = true; @@ -1527,13 +1527,13 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb); continue; - } + } else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) { - // not in library and not in agent's inventory + // not in library and not in agent's inventory LL_DEBUGS("Avatar") << "inventory item not in user inventory or library, skipping " << item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL; - continue; + continue; } else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) { @@ -1567,16 +1567,16 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, wearable_count-1); removeCOFItemLinks(item_id, cb); } - + items_to_link.push_back(item_to_wear); - } + } } break; case LLAssetType::AT_BODYPART: { // TODO: investigate wearables may not be loaded at this point EXT-8231 - + // Remove the existing wearables of the same type. // Remove existing body parts anyway because we must not be able to wear e.g. two skins. removeCOFLinksOfType(item_to_wear->getWearableType()); @@ -1587,7 +1587,7 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, items_to_link.push_back(item_to_wear); } break; - + case LLAssetType::AT_OBJECT: { rez_attachment(item_to_wear, NULL, replace); @@ -1601,14 +1601,14 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, // Batch up COF link creation - more efficient if using AIS. if (items_to_link.size()) { - link_inventory_array(getCOF(), items_to_link, cb); + link_inventory_array(getCOF(), items_to_link, cb); } } void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, - bool do_update, - bool replace, - LLPointer cb) + bool do_update, + bool replace, + LLPointer cb) { uuid_vec_t ids; ids.push_back(item_id_to_wear); @@ -1618,15 +1618,15 @@ void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, // Update appearance from outfit folder. void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append) { - if (!proceed) - return; - LLAppearanceMgr::instance().updateCOF(category,append); + if (!proceed) + return; + LLAppearanceMgr::instance().updateCOF(category,append); } void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit) { - LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); - wearInventoryCategory(cat, false, false); + LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); + wearInventoryCategory(cat, false, false); } // Remove existing photo link from outfit folder. @@ -1659,111 +1659,111 @@ void LLAppearanceMgr::removeOutfitPhoto(const LLUUID& outfit_id) // Open outfit renaming dialog. void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id) { - LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); - if (!cat) - { - return; - } + LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); + if (!cat) + { + return; + } - LLSD args; - args["NAME"] = cat->getName(); + LLSD args; + args["NAME"] = cat->getName(); - LLSD payload; - payload["cat_id"] = outfit_id; + LLSD payload; + payload["cat_id"] = outfit_id; - LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); + LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); } // User typed new outfit name. // static void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; // canceled + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled - std::string outfit_name = response["new_name"].asString(); - LLStringUtil::trim(outfit_name); - if (!outfit_name.empty()) - { - LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); - rename_category(&gInventory, cat_id, outfit_name); - } + std::string outfit_name = response["new_name"].asString(); + LLStringUtil::trim(outfit_name); + if (!outfit_name.empty()) + { + LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); + rename_category(&gInventory, cat_id, outfit_name); + } } void LLAppearanceMgr::setOutfitLocked(bool locked) { - if (mOutfitLocked == locked) - { - return; - } + if (mOutfitLocked == locked) + { + return; + } - mOutfitLocked = locked; - if (locked) - { - mUnlockOutfitTimer->start(); - } - else - { - mUnlockOutfitTimer->stop(); - } + mOutfitLocked = locked; + if (locked) + { + mUnlockOutfitTimer->start(); + } + else + { + mUnlockOutfitTimer->stop(); + } - LLOutfitObserver::instance().notifyOutfitLockChanged(); + LLOutfitObserver::instance().notifyOutfitLockChanged(); } void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id) { - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - wearInventoryCategory(cat, false, true); + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + wearInventoryCategory(cat, false, true); } void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); - - gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); - - LLInventoryModel::item_array_t::const_iterator it = items.begin(); - const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); - uuid_vec_t uuids_to_remove; - for( ; it_end != it; ++it) - { - LLViewerInventoryItem* item = *it; - uuids_to_remove.push_back(item->getUUID()); - } - removeItemsFromAvatar(uuids_to_remove); - - // deactivate all gestures in the outfit folder - LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE); - for(S32 i = 0; i < gest_items.size(); ++i) - { - LLViewerInventoryItem *gest_item = gest_items[i]; - if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) - { - LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); - } - } + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); + + gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); + + LLInventoryModel::item_array_t::const_iterator it = items.begin(); + const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); + uuid_vec_t uuids_to_remove; + for( ; it_end != it; ++it) + { + LLViewerInventoryItem* item = *it; + uuids_to_remove.push_back(item->getUUID()); + } + removeItemsFromAvatar(uuids_to_remove); + + // deactivate all gestures in the outfit folder + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE); + for(S32 i = 0; i < gest_items.size(); ++i) + { + LLViewerInventoryItem *gest_item = gest_items[i]; + if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) + { + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); + } + } } // Create a copy of src_id + contents as a subfolder of dst_id. void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, - LLPointer cb) -{ - LLInventoryCategory *src_cat = gInventory.getCategory(src_id); - if (!src_cat) - { - LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL; - return; - } - LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL; - LLUUID parent_id = dst_id; - if(parent_id.isNull()) - { - parent_id = gInventory.getRootFolderID(); - } - gInventory.createNewCategory( + LLPointer cb) +{ + LLInventoryCategory *src_cat = gInventory.getCategory(src_id); + if (!src_cat) + { + LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL; + return; + } + LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL; + LLUUID parent_id = dst_id; + if(parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + gInventory.createNewCategory( parent_id, LLFolderType::FT_NONE, src_cat->getName(), @@ -1778,326 +1778,326 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds } void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, - bool include_folder_links, LLPointer cb) -{ - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - LLSD contents = LLSD::emptyArray(); - gInventory.getDirectDescendentsOf(src_id, cats, items); - if (!cats || !items) - { - // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean - // that the cat just doesn't have any items or subfolders). - LLViewerInventoryCategory* category = gInventory.getCategory(src_id); - if (category) - { - LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; - } - else - { - LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; - } - llassert(cats != NULL && items != NULL); - - return; - } - - LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; - for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); - iter != items->end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - switch (item->getActualType()) - { - case LLAssetType::AT_LINK: - { - LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; - //getActualDescription() is used for a new description - //to propagate ordering information saved in descriptions of links - LLSD item_contents; - item_contents["name"] = item->getName(); - item_contents["desc"] = item->getActualDescription(); - item_contents["linked_id"] = item->getLinkedUUID(); - item_contents["type"] = LLAssetType::AT_LINK; - contents.append(item_contents); - break; - } - case LLAssetType::AT_LINK_FOLDER: - { - LLViewerInventoryCategory *catp = item->getLinkedCategory(); - if (catp && include_folder_links) - { - LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; - LLSD base_contents; - base_contents["name"] = catp->getName(); - base_contents["desc"] = ""; // categories don't have descriptions. - base_contents["linked_id"] = catp->getLinkedUUID(); - base_contents["type"] = LLAssetType::AT_LINK_FOLDER; - contents.append(base_contents); - } - break; - } - default: - { - // Linux refuses to compile unless all possible enums are handled. Really, Linux? - break; - } - } - } - slam_inventory_folder(dst_id, contents, cb); + bool include_folder_links, LLPointer cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + LLSD contents = LLSD::emptyArray(); + gInventory.getDirectDescendentsOf(src_id, cats, items); + if (!cats || !items) + { + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + LLViewerInventoryCategory* category = gInventory.getCategory(src_id); + if (category) + { + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; + } + else + { + LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; + } + llassert(cats != NULL && items != NULL); + + return; + } + + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + //getActualDescription() is used for a new description + //to propagate ordering information saved in descriptions of links + LLSD item_contents; + item_contents["name"] = item->getName(); + item_contents["desc"] = item->getActualDescription(); + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + if (catp && include_folder_links) + { + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + LLSD base_contents; + base_contents["name"] = catp->getName(); + base_contents["desc"] = ""; // categories don't have descriptions. + base_contents["linked_id"] = catp->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + break; + } + default: + { + // Linux refuses to compile unless all possible enums are handled. Really, Linux? + break; + } + } + } + slam_inventory_folder(dst_id, contents, cb); } // Copy contents of src_id to dst_id. void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, - LLPointer cb) -{ - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(src_id, cats, items); - LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; - LLInventoryObject::const_object_list_t link_array; - for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); - iter != items->end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - switch (item->getActualType()) - { - case LLAssetType::AT_LINK: - { - LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; - link_array.push_back(LLConstPointer(item)); - break; - } - case LLAssetType::AT_LINK_FOLDER: - { - LLViewerInventoryCategory *catp = item->getLinkedCategory(); - // Skip copying outfit links. - if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) - { - LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; - link_array.push_back(LLConstPointer(item)); - } - break; - } - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_OBJECT: - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_GESTURE: - { - LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; - copy_inventory_item(gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - dst_id, - item->getName(), - cb); - break; - } - default: - // Ignore non-outfit asset types - break; - } - } - if (!link_array.empty()) - { - link_inventory_array(dst_id, link_array, cb); - } + LLPointer cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(src_id, cats, items); + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + LLInventoryObject::const_object_list_t link_array; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer(item)); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + // Skip copying outfit links. + if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) + { + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer(item)); + } + break; + } + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_GESTURE: + { + LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + dst_id, + item->getName(), + cb); + break; + } + default: + // Ignore non-outfit asset types + break; + } + } + if (!link_array.empty()) + { + link_inventory_array(dst_id, link_array, cb); + } } BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) { - // These are the wearable items that are required for considering this - // folder as containing a complete outfit. - U32 required_wearables = 0; - required_wearables |= 1LL << LLWearableType::WT_SHAPE; - required_wearables |= 1LL << LLWearableType::WT_SKIN; - required_wearables |= 1LL << LLWearableType::WT_HAIR; - required_wearables |= 1LL << LLWearableType::WT_EYES; - - // These are the wearables that the folder actually contains. - U32 folder_wearables = 0; - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(folder_id, cats, items); - for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); - iter != items->end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - if (item->isWearableType()) - { - const LLWearableType::EType wearable_type = item->getWearableType(); - folder_wearables |= 1LL << wearable_type; - } - } - - // If the folder contains the required wearables, return TRUE. - return ((required_wearables & folder_wearables) == required_wearables); + // These are the wearable items that are required for considering this + // folder as containing a complete outfit. + U32 required_wearables = 0; + required_wearables |= 1LL << LLWearableType::WT_SHAPE; + required_wearables |= 1LL << LLWearableType::WT_SKIN; + required_wearables |= 1LL << LLWearableType::WT_HAIR; + required_wearables |= 1LL << LLWearableType::WT_EYES; + + // These are the wearables that the folder actually contains. + U32 folder_wearables = 0; + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, cats, items); + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + if (item->isWearableType()) + { + const LLWearableType::EType wearable_type = item->getWearableType(); + folder_wearables |= 1LL << wearable_type; + } + } + + // If the folder contains the required wearables, return TRUE. + return ((required_wearables & folder_wearables) == required_wearables); } bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) { - // Disallow removing the base outfit. - if (outfit_cat_id == getBaseOutfitUUID()) - { - return false; - } + // Disallow removing the base outfit. + if (outfit_cat_id == getBaseOutfitUUID()) + { + return false; + } - // Check if the outfit folder itself is removable. - if (!get_is_category_removable(&gInventory, outfit_cat_id)) - { - return false; - } + // Check if the outfit folder itself is removable. + if (!get_is_category_removable(&gInventory, outfit_cat_id)) + { + return false; + } - // Check for the folder's non-removable descendants. - LLFindNonRemovableObjects filter_non_removable; - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); - if (!cats.empty() || !items.empty()) - { - return false; - } + // Check for the folder's non-removable descendants. + LLFindNonRemovableObjects filter_non_removable; + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); + if (!cats.empty() || !items.empty()) + { + return false; + } - return true; + return true; } // static bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_worn); + return items.size() > 0; } // static bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) { - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + not_worn); - return items.size() > 0; + return items.size() > 0; } bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) { - // Don't allow wearing anything while we're changing appearance. - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } + // Don't allow wearing anything while we're changing appearance. + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } - // Check whether it's the base outfit. - if (outfit_cat_id.isNull()) - { - return false; - } + // Check whether it's the base outfit. + if (outfit_cat_id.isNull()) + { + return false; + } - // Check whether the outfit contains any wearables - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); + // Check whether the outfit contains any wearables + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable); - return items.size() > 0; + return items.size() > 0; } // Moved from LLWearableList::ContextMenu for wider utility. bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const { - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - U32 n_objects = 0; - U32 n_clothes = 0; - - // Count given clothes (by wearable type) and objects. - for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - const LLViewerInventoryItem* item = gInventory.getItem(*it); - if (!item) - { - return false; - } - - if (item->getType() == LLAssetType::AT_OBJECT) - { - ++n_objects; - } - else if (item->getType() == LLAssetType::AT_CLOTHING) - { - ++n_clothes; - } - else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE) - { - return isAgentAvatarValid(); - } - else - { - LL_WARNS() << "Unexpected wearable type" << LL_ENDL; - return false; - } - } - - // Check whether we can add all the objects. - if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects)) - { - return false; - } - - // Check whether we can add all the clothes. + // TODO: investigate wearables may not be loaded at this point EXT-8231 + + U32 n_objects = 0; + U32 n_clothes = 0; + + // Count given clothes (by wearable type) and objects. + for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) + { + const LLViewerInventoryItem* item = gInventory.getItem(*it); + if (!item) + { + return false; + } + + if (item->getType() == LLAssetType::AT_OBJECT) + { + ++n_objects; + } + else if (item->getType() == LLAssetType::AT_CLOTHING) + { + ++n_clothes; + } + else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE) + { + return isAgentAvatarValid(); + } + else + { + LL_WARNS() << "Unexpected wearable type" << LL_ENDL; + return false; + } + } + + // Check whether we can add all the objects. + if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects)) + { + return false; + } + + // Check whether we can add all the clothes. U32 sum_clothes = n_clothes + gAgentWearables.getClothingLayerCount(); return sum_clothes <= LLAgentWearables::MAX_CLOTHING_LAYERS; } void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer cb) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(category, cats, items, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i = 0; i < items.size(); ++i) - { - LLViewerInventoryItem *item = items.at(i); - if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) - continue; - LLViewerInventoryCategory* catp = item->getLinkedCategory(); - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - remove_inventory_item(item->getUUID(), cb); - } - } + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.size(); ++i) + { + LLViewerInventoryItem *item = items.at(i); + if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) + continue; + LLViewerInventoryCategory* catp = item->getLinkedCategory(); + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + remove_inventory_item(item->getUUID(), cb); + } + } } // Keep the last N wearables of each type. For viewer 2.0, N is 1 for // both body parts and clothing items. void LLAppearanceMgr::filterWearableItems( - LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total) + LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total) { // Restrict by max total items first. if ((max_total > 0) && (items.size() > max_total)) @@ -2134,348 +2134,348 @@ void LLAppearanceMgr::filterWearableItems( void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { - LLViewerInventoryCategory *pcat = gInventory.getCategory(category); - if (!pcat) - { - LL_WARNS() << "no category found for id " << category << LL_ENDL; - return; - } - LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; - - const LLUUID cof = getCOF(); - - // Deactivate currently active gestures in the COF, if replacing outfit - if (!append) - { - LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); - for(S32 i = 0; i < gest_items.size(); ++i) - { - LLViewerInventoryItem *gest_item = gest_items.at(i); - if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) - { - LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); - } - } - } - - // Collect and filter descendents to determine new COF contents. - - // - Body parts: always include COF contents as a fallback in case any - // required parts are missing. - // Preserve body parts from COF if appending. - LLInventoryModel::item_array_t body_items; - getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); - if (append) - reverse(body_items.begin(), body_items.end()); - // Reduce body items to max of one per type. - removeDuplicateItems(body_items); - filterWearableItems(body_items, 1, 0); - - // - Wearables: include COF contents only if appending. - LLInventoryModel::item_array_t wear_items; - if (append) - getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); - // Reduce wearables to max of one per type. - removeDuplicateItems(wear_items); - filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); - - // - Attachments: include COF contents only if appending. - LLInventoryModel::item_array_t obj_items; - if (append) - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); - removeDuplicateItems(obj_items); - - // - Gestures: include COF contents only if appending. - LLInventoryModel::item_array_t gest_items; - if (append) - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); - removeDuplicateItems(gest_items); - - // Create links to new COF contents. - LLInventoryModel::item_array_t all_items; - std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items)); - std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items)); - std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); - std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); - - // Find any wearables that need description set to enforce ordering. - desc_map_t desc_map; - getWearableOrderingDescUpdates(wear_items, desc_map); - - // Will link all the above items. - // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). - LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(false,false); - LLSD contents = LLSD::emptyArray(); - - for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); - it != all_items.end(); ++it) - { - LLSD item_contents; - LLInventoryItem *item = *it; - - std::string desc; - desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); - if (desc_iter != desc_map.end()) - { - desc = desc_iter->second; - LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc - << " (was: " << item->getActualDescription() << ")" << LL_ENDL; - } - else - { - desc = item->getActualDescription(); - } - - item_contents["name"] = item->getName(); - item_contents["desc"] = desc; - item_contents["linked_id"] = item->getLinkedUUID(); - item_contents["type"] = LLAssetType::AT_LINK; - contents.append(item_contents); - } - const LLUUID& base_id = append ? getBaseOutfitUUID() : category; - LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); - if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) - { - LLSD base_contents; - base_contents["name"] = base_cat->getName(); - base_contents["desc"] = ""; - base_contents["linked_id"] = base_cat->getLinkedUUID(); - base_contents["type"] = LLAssetType::AT_LINK_FOLDER; - contents.append(base_contents); - } - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) - { - dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); - } - slam_inventory_folder(getCOF(), contents, link_waiter); - - LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; -} + LLViewerInventoryCategory *pcat = gInventory.getCategory(category); + if (!pcat) + { + LL_WARNS() << "no category found for id " << category << LL_ENDL; + return; + } + LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; -void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) -{ - LLSidepanelAppearance* panel_appearance = - dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel_appearance) - { - panel_appearance->refreshCurrentOutfitName(name); - } -} + const LLUUID cof = getCOF(); + + // Deactivate currently active gestures in the COF, if replacing outfit + if (!append) + { + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + for(S32 i = 0; i < gest_items.size(); ++i) + { + LLViewerInventoryItem *gest_item = gest_items.at(i); + if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) + { + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); + } + } + } + + // Collect and filter descendents to determine new COF contents. + + // - Body parts: always include COF contents as a fallback in case any + // required parts are missing. + // Preserve body parts from COF if appending. + LLInventoryModel::item_array_t body_items; + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); + if (append) + reverse(body_items.begin(), body_items.end()); + // Reduce body items to max of one per type. + removeDuplicateItems(body_items); + filterWearableItems(body_items, 1, 0); + + // - Wearables: include COF contents only if appending. + LLInventoryModel::item_array_t wear_items; + if (append) + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); + // Reduce wearables to max of one per type. + removeDuplicateItems(wear_items); + filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); + + // - Attachments: include COF contents only if appending. + LLInventoryModel::item_array_t obj_items; + if (append) + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); + removeDuplicateItems(obj_items); + + // - Gestures: include COF contents only if appending. + LLInventoryModel::item_array_t gest_items; + if (append) + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); + removeDuplicateItems(gest_items); + + // Create links to new COF contents. + LLInventoryModel::item_array_t all_items; + std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items)); + std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items)); + std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); + std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); + + // Find any wearables that need description set to enforce ordering. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + // Will link all the above items. + // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). + LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(false,false); + LLSD contents = LLSD::emptyArray(); + + for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); + it != all_items.end(); ++it) + { + LLSD item_contents; + LLInventoryItem *item = *it; + + std::string desc; + desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); + if (desc_iter != desc_map.end()) + { + desc = desc_iter->second; + LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + } + else + { + desc = item->getActualDescription(); + } + + item_contents["name"] = item->getName(); + item_contents["desc"] = desc; + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + } + const LLUUID& base_id = append ? getBaseOutfitUUID() : category; + LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); + if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) + { + LLSD base_contents; + base_contents["name"] = base_cat->getName(); + base_contents["desc"] = ""; + base_contents["linked_id"] = base_cat->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); + } + slam_inventory_folder(getCOF(), contents, link_waiter); + + LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; +} + +void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) +{ + LLSidepanelAppearance* panel_appearance = + dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel_appearance) + { + panel_appearance->refreshCurrentOutfitName(name); + } +} void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer link_waiter) { - const LLUUID cof = getCOF(); - LLViewerInventoryCategory* catp = gInventory.getCategory(category); - std::string new_outfit_name = ""; + const LLUUID cof = getCOF(); + LLViewerInventoryCategory* catp = gInventory.getCategory(category); + std::string new_outfit_name = ""; - purgeBaseOutfitLink(cof, link_waiter); + purgeBaseOutfitLink(cof, link_waiter); + + if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + link_inventory_object(cof, catp, link_waiter); + new_outfit_name = catp->getName(); + } - if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - link_inventory_object(cof, catp, link_waiter); - new_outfit_name = catp->getName(); - } - - updatePanelOutfitName(new_outfit_name); + updatePanelOutfitName(new_outfit_name); } void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) { - LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; - LLInventoryItem::item_array_t items; - std::vector< LLViewerWearable* > wearables; - wearables.reserve(32); - - // For each wearable type, find the wearables of that type. - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) - { - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); - iter != holder->getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - LLViewerWearable* wearable = data.mWearable; - if( wearable && ((S32)wearable->getType() == i) ) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); - if( item && (item->getAssetUUID() == wearable->getAssetID()) ) - { - items.push_back(item); - wearables.push_back(wearable); - } - } - } - } - - if(wearables.size() > 0) - { - gAgentWearables.setWearableOutfit(items, wearables); - } + LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; + LLInventoryItem::item_array_t items; + std::vector< LLViewerWearable* > wearables; + wearables.reserve(32); + + // For each wearable type, find the wearables of that type. + for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + { + for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); + iter != holder->getFoundList().end(); ++iter) + { + LLFoundData& data = *iter; + LLViewerWearable* wearable = data.mWearable; + if( wearable && ((S32)wearable->getType() == i) ) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); + if( item && (item->getAssetUUID() == wearable->getAssetID()) ) + { + items.push_back(item); + wearables.push_back(wearable); + } + } + } + } + + if(wearables.size() > 0) + { + gAgentWearables.setWearableOutfit(items, wearables); + } } S32 LLAppearanceMgr::countActiveHoldingPatterns() { - return LLWearableHoldingPattern::countActive(); + return LLWearableHoldingPattern::countActive(); } static void remove_non_link_items(LLInventoryModel::item_array_t &items) { - LLInventoryModel::item_array_t pruned_items; - for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); - iter != items.end(); - ++iter) - { - const LLViewerInventoryItem *item = (*iter); - if (item && item->getIsLinkType()) - { - pruned_items.push_back((*iter)); - } - } - items = pruned_items; + LLInventoryModel::item_array_t pruned_items; + for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); + iter != items.end(); + ++iter) + { + const LLViewerInventoryItem *item = (*iter); + if (item && item->getIsLinkType()) + { + pruned_items.push_back((*iter)); + } + } + items = pruned_items; } //a predicate for sorting inventory items by actual descriptions bool sort_by_actual_description(const LLInventoryItem* item1, const LLInventoryItem* item2) { - if (!item1 || !item2) - { - LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; - return true; - } + if (!item1 || !item2) + { + LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; + return true; + } - return item1->getActualDescription() < item2->getActualDescription(); + return item1->getActualDescription() < item2->getActualDescription(); } void item_array_diff(LLInventoryModel::item_array_t& full_list, - LLInventoryModel::item_array_t& keep_list, - LLInventoryModel::item_array_t& kill_list) - -{ - for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); - it != full_list.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end()) - { - kill_list.push_back(item); - } - } + LLInventoryModel::item_array_t& keep_list, + LLInventoryModel::item_array_t& kill_list) + +{ + for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); + it != full_list.end(); + ++it) + { + LLViewerInventoryItem *item = *it; + if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end()) + { + kill_list.push_back(item); + } + } } S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, - LLAssetType::EType type, - S32 max_items_per_type, - S32 max_items_total, - LLInventoryObject::object_list_t& items_to_kill) -{ - S32 to_kill_count = 0; - - LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(cat_id, items, type); - LLInventoryModel::item_array_t curr_items = items; - removeDuplicateItems(items); - if (max_items_per_type > 0 || max_items_total > 0) - { - filterWearableItems(items, max_items_per_type, max_items_total); - } - LLInventoryModel::item_array_t kill_items; - item_array_diff(curr_items,items,kill_items); - for (LLInventoryModel::item_array_t::iterator it = kill_items.begin(); - it != kill_items.end(); - ++it) - { - items_to_kill.push_back(LLPointer(*it)); - to_kill_count++; - } - return to_kill_count; -} - + LLAssetType::EType type, + S32 max_items_per_type, + S32 max_items_total, + LLInventoryObject::object_list_t& items_to_kill) +{ + S32 to_kill_count = 0; + + LLInventoryModel::item_array_t items; + getDescendentsOfAssetType(cat_id, items, type); + LLInventoryModel::item_array_t curr_items = items; + removeDuplicateItems(items); + if (max_items_per_type > 0 || max_items_total > 0) + { + filterWearableItems(items, max_items_per_type, max_items_total); + } + LLInventoryModel::item_array_t kill_items; + item_array_diff(curr_items,items,kill_items); + for (LLInventoryModel::item_array_t::iterator it = kill_items.begin(); + it != kill_items.end(); + ++it) + { + items_to_kill.push_back(LLPointer(*it)); + to_kill_count++; + } + return to_kill_count; +} + void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, - LLInventoryObject::object_list_t& items_to_kill) + LLInventoryObject::object_list_t& items_to_kill) { - findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, - 1, 0, items_to_kill); - findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, - 0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill); - findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, - 0, 0, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, + 1, 0, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, + 0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, + 0, 0, items_to_kill); } void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer cb) { - LLInventoryObject::object_list_t items_to_kill; - findAllExcessOrDuplicateItems(getCOF(), items_to_kill); - if (items_to_kill.size()>0) - { - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - remove_inventory_items(items_to_kill, cb); - } + LLInventoryObject::object_list_t items_to_kill; + findAllExcessOrDuplicateItems(getCOF(), items_to_kill); + if (items_to_kill.size()>0) + { + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + remove_inventory_items(items_to_kill, cb); + } } bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2) { - if (!item1 || !item2) - { - LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL; - return true; - } + if (!item1 || !item2) + { + LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL; + return true; + } - return item1->getLinkedUUID() < item2->getLinkedUUID(); + return item1->getLinkedUUID() < item2->getLinkedUUID(); } void get_sorted_base_and_cof_items(LLInventoryModel::item_array_t& cof_item_array, LLInventoryModel::item_array_t& outfit_item_array) { - LLUUID base_outfit_id = LLAppearanceMgr::instance().getBaseOutfitUUID(); + LLUUID base_outfit_id = LLAppearanceMgr::instance().getBaseOutfitUUID(); - if (base_outfit_id.notNull()) - { - LLIsValidItemLink collector; - LLInventoryModel::cat_array_t sub_cat_array; + if (base_outfit_id.notNull()) + { + LLIsValidItemLink collector; + LLInventoryModel::cat_array_t sub_cat_array; - gInventory.collectDescendents(base_outfit_id, - sub_cat_array, - outfit_item_array, - LLInventoryModel::EXCLUDE_TRASH); + gInventory.collectDescendents(base_outfit_id, + sub_cat_array, + outfit_item_array, + LLInventoryModel::EXCLUDE_TRASH); - LLInventoryModel::cat_array_t cof_cats; + LLInventoryModel::cat_array_t cof_cats; - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cof_cats, cof_item_array, - LLInventoryModel::EXCLUDE_TRASH, collector); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cof_cats, cof_item_array, + LLInventoryModel::EXCLUDE_TRASH, collector); - for (U32 i = 0; i < outfit_item_array.size(); ++i) - { - LLViewerInventoryItem* linked_item = outfit_item_array.at(i)->getLinkedItem(); - if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) - { - outfit_item_array.erase(outfit_item_array.begin() + i); - break; - } - } + for (U32 i = 0; i < outfit_item_array.size(); ++i) + { + LLViewerInventoryItem* linked_item = outfit_item_array.at(i)->getLinkedItem(); + if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + outfit_item_array.erase(outfit_item_array.begin() + i); + break; + } + } - std::sort(cof_item_array.begin(), cof_item_array.end(), sort_by_linked_uuid); - std::sort(outfit_item_array.begin(), outfit_item_array.end(), sort_by_linked_uuid); - } + std::sort(cof_item_array.begin(), cof_item_array.end(), sort_by_linked_uuid); + std::sort(outfit_item_array.begin(), outfit_item_array.end(), sort_by_linked_uuid); + } } void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, - bool enforce_ordering, - nullary_func_t post_update_func) + bool enforce_ordering, + nullary_func_t post_update_func) { - if (mIsInUpdateAppearanceFromCOF) - { - LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL; - return; - } + if (mIsInUpdateAppearanceFromCOF) + { + LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL; + return; + } - LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; if (gInventory.hasPosiblyBrockenLinks()) { @@ -2510,263 +2510,263 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, } } - if (enforce_item_restrictions) - { - // The point here is just to call - // updateAppearanceFromCOF() again after excess items - // have been removed. That time we will set - // enforce_item_restrictions to false so we don't get - // caught in a perpetual loop. - LLPointer cb( - new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); - enforceCOFItemRestrictions(cb); - return; - } - - if (enforce_ordering) - { - //checking integrity of the COF in terms of ordering of wearables, - //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - - // As with enforce_item_restrictions handling above, we want - // to wait for the update callbacks, then (finally!) call - // updateAppearanceFromCOF() with no additional COF munging needed. - LLPointer cb( - new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); - updateClothingOrderingInfo(LLUUID::null, cb); - return; - } - - if (!validateClothingOrderingInfo()) - { - - LLInventoryModel::item_array_t outfit_item_array; - LLInventoryModel::item_array_t cof_item_array; - get_sorted_base_and_cof_items(cof_item_array, outfit_item_array); - - if (outfit_item_array.size() == cof_item_array.size()) - { - for (U32 i = 0; i < cof_item_array.size(); ++i) - { - LLViewerInventoryItem *cof_it = cof_item_array.at(i); - LLViewerInventoryItem *base_it = outfit_item_array.at(i); - - if (cof_it->getActualDescription() != base_it->getActualDescription()) - { - if (cof_it->getLinkedUUID() == base_it->getLinkedUUID()) - { - cof_it->setDescription(base_it->getActualDescription()); - gInventory.updateItem(cof_it); - } - } - } - LLAppearanceMgr::getInstance()->updateIsDirty(); - } - - } - - BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - selfStartPhase("update_appearance_from_cof"); - - // update dirty flag to see if the state of the COF matches - // the saved outfit stored as a folder link - updateIsDirty(); - - // Send server request for appearance update - if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) - { - requestServerAppearanceUpdate(); - } - - LLUUID current_outfit_id = getCOF(); - - // Find all the wearables that are in the COF's subtree. - LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL; - LLInventoryModel::item_array_t wear_items; - LLInventoryModel::item_array_t obj_items; - LLInventoryModel::item_array_t gest_items; - getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); - // Get rid of non-links in case somehow the COF was corrupted. - remove_non_link_items(wear_items); - remove_non_link_items(obj_items); - remove_non_link_items(gest_items); - - dumpItemArray(wear_items,"asset_dump: wear_item"); - dumpItemArray(obj_items,"asset_dump: obj_item"); - - LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); - if (!gInventory.isCategoryComplete(current_outfit_id)) - { - LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() - << " descendent_count " << cof->getDescendentCount() - << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; - } - if(!wear_items.size()) - { - LLNotificationsUtil::add("CouldNotPutOnOutfit"); - return; - } - - //preparing the list of wearables in the correct order for LLAgentWearables - sortItemsByActualDescription(wear_items); - - - LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; - LLTimer hp_block_timer; - LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; - - holder->setObjItems(obj_items); - holder->setGestItems(gest_items); - - // Note: can't do normal iteration, because if all the - // wearables can be resolved immediately, then the - // callback will be called (and this object deleted) - // before the final getNextData(). - - for(S32 i = 0; i < wear_items.size(); ++i) - { - LLViewerInventoryItem *item = wear_items.at(i); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - - // Fault injection: use debug setting to test asset - // fetch failures (should be replaced by new defaults in - // lost&found). - U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); - - if (item && item->getIsLinkType() && linked_item) - { - LLFoundData found(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID - ); - - if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) - { - found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB - } - //pushing back, not front, to preserve order of wearables for LLAgentWearables - holder->getFoundList().push_back(found); - } - else - { - if (!item) - { - LL_WARNS() << "Attempt to wear a null item " << LL_ENDL; - } - else if (!linked_item) - { - LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL; - } - } - } - - selfStartPhase("get_wearables_2"); - - for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); - it != holder->getFoundList().end(); ++it) - { - LLFoundData& found = *it; - - LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL; - - // Fetch the wearables about to be worn. - LLWearableList::instance().getAsset(found.mAssetID, - found.mName, - gAgentAvatarp, - found.mAssetType, - onWearableAssetFetch, - (void*)holder); - - } - - holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); - if (!holder->pollFetchCompletion()) - { - doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); - } - post_update_func(); - - LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; + if (enforce_item_restrictions) + { + // The point here is just to call + // updateAppearanceFromCOF() again after excess items + // have been removed. That time we will set + // enforce_item_restrictions to false so we don't get + // caught in a perpetual loop. + LLPointer cb( + new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); + enforceCOFItemRestrictions(cb); + return; + } + + if (enforce_ordering) + { + //checking integrity of the COF in terms of ordering of wearables, + //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) + + // As with enforce_item_restrictions handling above, we want + // to wait for the update callbacks, then (finally!) call + // updateAppearanceFromCOF() with no additional COF munging needed. + LLPointer cb( + new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); + updateClothingOrderingInfo(LLUUID::null, cb); + return; + } + + if (!validateClothingOrderingInfo()) + { + + LLInventoryModel::item_array_t outfit_item_array; + LLInventoryModel::item_array_t cof_item_array; + get_sorted_base_and_cof_items(cof_item_array, outfit_item_array); + + if (outfit_item_array.size() == cof_item_array.size()) + { + for (U32 i = 0; i < cof_item_array.size(); ++i) + { + LLViewerInventoryItem *cof_it = cof_item_array.at(i); + LLViewerInventoryItem *base_it = outfit_item_array.at(i); + + if (cof_it->getActualDescription() != base_it->getActualDescription()) + { + if (cof_it->getLinkedUUID() == base_it->getLinkedUUID()) + { + cof_it->setDescription(base_it->getActualDescription()); + gInventory.updateItem(cof_it); + } + } + } + LLAppearanceMgr::getInstance()->updateIsDirty(); + } + + } + + BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); + selfStartPhase("update_appearance_from_cof"); + + // update dirty flag to see if the state of the COF matches + // the saved outfit stored as a folder link + updateIsDirty(); + + // Send server request for appearance update + if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) + { + requestServerAppearanceUpdate(); + } + + LLUUID current_outfit_id = getCOF(); + + // Find all the wearables that are in the COF's subtree. + LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL; + LLInventoryModel::item_array_t wear_items; + LLInventoryModel::item_array_t obj_items; + LLInventoryModel::item_array_t gest_items; + getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); + // Get rid of non-links in case somehow the COF was corrupted. + remove_non_link_items(wear_items); + remove_non_link_items(obj_items); + remove_non_link_items(gest_items); + + dumpItemArray(wear_items,"asset_dump: wear_item"); + dumpItemArray(obj_items,"asset_dump: obj_item"); + + LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); + if (!gInventory.isCategoryComplete(current_outfit_id)) + { + LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() + << " descendent_count " << cof->getDescendentCount() + << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; + } + if(!wear_items.size()) + { + LLNotificationsUtil::add("CouldNotPutOnOutfit"); + return; + } + + //preparing the list of wearables in the correct order for LLAgentWearables + sortItemsByActualDescription(wear_items); + + + LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; + LLTimer hp_block_timer; + LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; + + holder->setObjItems(obj_items); + holder->setGestItems(gest_items); + + // Note: can't do normal iteration, because if all the + // wearables can be resolved immediately, then the + // callback will be called (and this object deleted) + // before the final getNextData(). + + for(S32 i = 0; i < wear_items.size(); ++i) + { + LLViewerInventoryItem *item = wear_items.at(i); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + + // Fault injection: use debug setting to test asset + // fetch failures (should be replaced by new defaults in + // lost&found). + U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); + + if (item && item->getIsLinkType() && linked_item) + { + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID + ); + + if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } + //pushing back, not front, to preserve order of wearables for LLAgentWearables + holder->getFoundList().push_back(found); + } + else + { + if (!item) + { + LL_WARNS() << "Attempt to wear a null item " << LL_ENDL; + } + else if (!linked_item) + { + LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL; + } + } + } + + selfStartPhase("get_wearables_2"); + + for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); + it != holder->getFoundList().end(); ++it) + { + LLFoundData& found = *it; + + LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL; + + // Fetch the wearables about to be worn. + LLWearableList::instance().getAsset(found.mAssetID, + found.mName, + gAgentAvatarp, + found.mAssetType, + onWearableAssetFetch, + (void*)holder); + + } + + holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); + if (!holder->pollFetchCompletion()) + { + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); + } + post_update_func(); + + LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; } void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category, - LLInventoryModel::item_array_t& items, - LLAssetType::EType type) -{ - LLInventoryModel::cat_array_t cats; - LLIsType is_of_type(type); - gInventory.collectDescendentsIf(category, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_of_type); -} - -void LLAppearanceMgr::getUserDescendents(const LLUUID& category, - LLInventoryModel::item_array_t& wear_items, - LLInventoryModel::item_array_t& obj_items, - LLInventoryModel::item_array_t& gest_items) -{ - LLInventoryModel::cat_array_t wear_cats; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(category, - wear_cats, - wear_items, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); - - LLInventoryModel::cat_array_t obj_cats; - LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(category, - obj_cats, - obj_items, - LLInventoryModel::EXCLUDE_TRASH, - is_object); - - // Find all gestures in this folder - LLInventoryModel::cat_array_t gest_cats; - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(category, - gest_cats, - gest_items, - LLInventoryModel::EXCLUDE_TRASH, - is_gesture); + LLInventoryModel::item_array_t& items, + LLAssetType::EType type) +{ + LLInventoryModel::cat_array_t cats; + LLIsType is_of_type(type); + gInventory.collectDescendentsIf(category, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_of_type); +} + +void LLAppearanceMgr::getUserDescendents(const LLUUID& category, + LLInventoryModel::item_array_t& wear_items, + LLInventoryModel::item_array_t& obj_items, + LLInventoryModel::item_array_t& gest_items) +{ + LLInventoryModel::cat_array_t wear_cats; + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(category, + wear_cats, + wear_items, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable); + + LLInventoryModel::cat_array_t obj_cats; + LLIsType is_object( LLAssetType::AT_OBJECT ); + gInventory.collectDescendentsIf(category, + obj_cats, + obj_items, + LLInventoryModel::EXCLUDE_TRASH, + is_object); + + // Find all gestures in this folder + LLInventoryModel::cat_array_t gest_cats; + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + gInventory.collectDescendentsIf(category, + gest_cats, + gest_items, + LLInventoryModel::EXCLUDE_TRASH, + is_gesture); } void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) { - if(!category) return; + if(!category) return; - selfClearPhases(); - selfStartPhase("wear_inventory_category"); + selfClearPhases(); + selfStartPhase("wear_inventory_category"); - gAgentWearables.notifyLoadingStarted(); + gAgentWearables.notifyLoadingStarted(); - LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() - << " )" << LL_ENDL; + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() + << " )" << LL_ENDL; - // If we are copying from library, attempt to use AIS to copy the category. + // If we are copying from library, attempt to use AIS to copy the category. if (copy && AISAPI::isAvailable()) - { - LLUUID parent_id; - parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - if (parent_id.isNull()) - { - parent_id = gInventory.getRootFolderID(); - } - - LLPointer copy_cb = new LLWearCategoryAfterCopy(append); - LLPointer track_cb = new LLTrackPhaseWrapper( - std::string("wear_inventory_category_callback"), copy_cb); + { + LLUUID parent_id; + parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + if (parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + + LLPointer copy_cb = new LLWearCategoryAfterCopy(append); + LLPointer track_cb = new LLTrackPhaseWrapper( + std::string("wear_inventory_category_callback"), copy_cb); AISAPI::completion_t cr = boost::bind(&doAppearanceCb, track_cb, _1); AISAPI::CopyLibraryCategory(category->getUUID(), parent_id, false, cr); - } + } else - { - selfStartPhase("wear_inventory_category_fetch"); + { + selfStartPhase("wear_inventory_category_fetch"); if (AISAPI::isAvailable() && category->getPreferredType() == LLFolderType::FT_OUTFIT) { // for reliability just fetch it whole, linked items included @@ -2784,66 +2784,66 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool &LLAppearanceMgr::instance(), category->getUUID(), copy, append)); } - } + } } S32 LLAppearanceMgr::getActiveCopyOperations() const { - return LLCallAfterInventoryCopyMgr::getInstanceCount(); + return LLCallAfterInventoryCopyMgr::getInstanceCount(); } void LLAppearanceMgr::wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append) { - LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; - - selfStopPhase("wear_inventory_category_fetch"); - - // We now have an outfit ready to be copied to agent inventory. Do - // it, and wear that outfit normally. - LLInventoryCategory* cat = gInventory.getCategory(cat_id); - if(copy_items) - { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(cat_id, cats, items); - std::string name; - if(!cat) - { - // should never happen. - name = "New Outfit"; - } - else - { - name = cat->getName(); - } - LLViewerInventoryItem* item = NULL; - LLInventoryModel::item_array_t::const_iterator it = items->begin(); - LLInventoryModel::item_array_t::const_iterator end = items->end(); - LLUUID pid; - for(; it < end; ++it) - { - item = *it; - if(item) - { - if(LLInventoryType::IT_GESTURE == item->getInventoryType()) - { - pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); - } - else - { - pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - } - break; - } - } - if(pid.isNull()) - { - pid = gInventory.getRootFolderID(); - } - - gInventory.createNewCategory( - pid, - LLFolderType::FT_NONE, + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; + + selfStopPhase("wear_inventory_category_fetch"); + + // We now have an outfit ready to be copied to agent inventory. Do + // it, and wear that outfit normally. + LLInventoryCategory* cat = gInventory.getCategory(cat_id); + if(copy_items) + { + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + std::string name; + if(!cat) + { + // should never happen. + name = "New Outfit"; + } + else + { + name = cat->getName(); + } + LLViewerInventoryItem* item = NULL; + LLInventoryModel::item_array_t::const_iterator it = items->begin(); + LLInventoryModel::item_array_t::const_iterator end = items->end(); + LLUUID pid; + for(; it < end; ++it) + { + item = *it; + if(item) + { + if(LLInventoryType::IT_GESTURE == item->getInventoryType()) + { + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + } + else + { + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + } + break; + } + } + if(pid.isNull()) + { + pid = gInventory.getRootFolderID(); + } + + gInventory.createNewCategory( + pid, + LLFolderType::FT_NONE, name, [cat_id, append](const LLUUID& new_cat_id) { @@ -2863,205 +2863,205 @@ void LLAppearanceMgr::wearCategoryFinal(const LLUUID& cat_id, bool copy_items, b }, cat->getThumbnailUUID() ); - } - else - { - // Wear the inventory category. - LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append); - } + } + else + { + // Wear the inventory category. + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append); + } } // *NOTE: hack to get from avatar inventory to avatar void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append ) { - // Avoid unintentionally overwriting old wearables. We have to do - // this up front to avoid having to deal with the case of multiple - // wearables being dirty. - if (!category) return; + // Avoid unintentionally overwriting old wearables. We have to do + // this up front to avoid having to deal with the case of multiple + // wearables being dirty. + if (!category) return; - if ( !LLInventoryCallbackManager::is_instantiated() ) - { - // shutting down, ignore. - return; - } + if ( !LLInventoryCallbackManager::is_instantiated() ) + { + // shutting down, ignore. + return; + } - LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() - << "'" << LL_ENDL; - LLUIUsage::instance().logCommand("Avatar.WearCategory"); - - if (gAgentCamera.cameraCustomizeAvatar()) - { - // switching to outfit editor should automagically save any currently edited wearable - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); - } + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() + << "'" << LL_ENDL; + LLUIUsage::instance().logCommand("Avatar.WearCategory"); + + if (gAgentCamera.cameraCustomizeAvatar()) + { + // switching to outfit editor should automagically save any currently edited wearable + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); + } - LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); + LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } // FIXME do we really want to search entire inventory for matching name? void LLAppearanceMgr::wearOutfitByName(const std::string& name) { - LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(name); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - bool copy_items = false; - LLInventoryCategory* cat = NULL; - if (cat_array.size() > 0) - { - // Just wear the first one that matches - cat = cat_array.at(0); - } - else - { - gInventory.collectDescendentsIf(LLUUID::null, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - has_name); - if(cat_array.size() > 0) - { - cat = cat_array.at(0); - copy_items = true; - } - } - - if(cat) - { - LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); - } - else - { - LL_WARNS() << "Couldn't find outfit " < 0) + { + // Just wear the first one that matches + cat = cat_array.at(0); + } + else + { + gInventory.collectDescendentsIf(LLUUID::null, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + has_name); + if(cat_array.size() > 0) + { + cat = cat_array.at(0); + copy_items = true; + } + } + + if(cat) + { + LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); + } + else + { + LL_WARNS() << "Couldn't find outfit " <isWearableType() && b->isWearableType() && - (a->getWearableType() == b->getWearableType())); + return (a->isWearableType() && b->isWearableType() && + (a->getWearableType() == b->getWearableType())); } class LLDeferredCOFLinkObserver: public LLInventoryObserver { public: - LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer cb, const std::string& description): - mItemID(item_id), - mCallback(cb), - mDescription(description) - { - } - - ~LLDeferredCOFLinkObserver() - { - } - - /* virtual */ void changed(U32 mask) - { - const LLInventoryItem *item = gInventory.getItem(mItemID); - if (item) - { - gInventory.removeObserver(this); - LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); - delete this; - } - } + LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer cb, const std::string& description): + mItemID(item_id), + mCallback(cb), + mDescription(description) + { + } + + ~LLDeferredCOFLinkObserver() + { + } + + /* virtual */ void changed(U32 mask) + { + const LLInventoryItem *item = gInventory.getItem(mItemID); + if (item) + { + gInventory.removeObserver(this); + LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); + delete this; + } + } private: - const LLUUID mItemID; - std::string mDescription; - LLPointer mCallback; + const LLUUID mItemID; + std::string mDescription; + LLPointer mCallback; }; // BAP - note that this runs asynchronously if the item is not already loaded from inventory. // Dangerous if caller assumes link will exist after calling the function. void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, - LLPointer cb, - const std::string description) + LLPointer cb, + const std::string description) { - const LLInventoryItem *item = gInventory.getItem(item_id); - if (!item) - { - LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); - gInventory.addObserver(observer); - } - else - { - addCOFItemLink(item, cb, description); - } + const LLInventoryItem *item = gInventory.getItem(item_id); + if (!item) + { + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); + gInventory.addObserver(observer); + } + else + { + addCOFItemLink(item, cb, description); + } } void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, - LLPointer cb, - const std::string description) -{ - const LLViewerInventoryItem *vitem = dynamic_cast(item); - if (!vitem) - { - LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL; - return; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID()); - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::getCOF(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - bool linked_already = false; - for (S32 i=0; igetWearableType(); - - const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) - || (wearable_type == LLWearableType::WT_HAIR) - || (wearable_type == LLWearableType::WT_EYES) - || (wearable_type == LLWearableType::WT_SKIN); - - if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) - { - linked_already = true; - } - // Are these links to different items of the same body part - // type? If so, new item will replace old. - else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) - { - if (is_body_part && inv_item->getIsLinkType()) - { - remove_inventory_item(inv_item->getUUID(), cb); - } - else if (!gAgentWearables.canAddWearable(wearable_type)) - { - // MULTI-WEARABLES: make sure we don't go over clothing limits - remove_inventory_item(inv_item->getUUID(), cb); - } - } - } - - if (!linked_already) - { - LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; - copy_item->copyViewerItem(vitem); - copy_item->setDescription(description); - link_inventory_object(getCOF(), copy_item, cb); - } + LLPointer cb, + const std::string description) +{ + const LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem) + { + LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL; + return; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID()); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + bool linked_already = false; + for (S32 i=0; igetWearableType(); + + const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) + || (wearable_type == LLWearableType::WT_HAIR) + || (wearable_type == LLWearableType::WT_EYES) + || (wearable_type == LLWearableType::WT_SKIN); + + if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) + { + linked_already = true; + } + // Are these links to different items of the same body part + // type? If so, new item will replace old. + else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) + { + if (is_body_part && inv_item->getIsLinkType()) + { + remove_inventory_item(inv_item->getUUID(), cb); + } + else if (!gAgentWearables.canAddWearable(wearable_type)) + { + // MULTI-WEARABLES: make sure we don't go over clothing limits + remove_inventory_item(inv_item->getUUID(), cb); + } + } + } + + if (!linked_already) + { + LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; + copy_item->copyViewerItem(vitem); + copy_item->setDescription(description); + link_inventory_object(getCOF(), copy_item, cb); + } } LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) { - LLInventoryModel::item_array_t result; + LLInventoryModel::item_array_t result; LLUUID linked_id = gInventory.getLinkedItemID(item_id); LLInventoryModel::cat_array_t cat_array; @@ -3072,238 +3072,238 @@ LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& i LLInventoryModel::EXCLUDE_TRASH); for (S32 i=0; igetLinkedUUID() == linked_id) + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + if (inv_item->getLinkedUUID() == linked_id) + { + result.push_back(item_array.at(i)); + } + } + return result; +} + +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +{ + LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); + return links.size() > 0; +} + +void LLAppearanceMgr::removeAllClothesFromAvatar() +{ + // Fetch worn clothes (i.e. the ones in COF). + LLInventoryModel::item_array_t clothing_items; + LLInventoryModel::cat_array_t dummy; + LLIsType is_clothing(LLAssetType::AT_CLOTHING); + gInventory.collectDescendentsIf(getCOF(), + dummy, + clothing_items, + LLInventoryModel::EXCLUDE_TRASH, + is_clothing); + uuid_vec_t item_ids; + for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); + it != clothing_items.end(); ++it) + { + item_ids.push_back((*it).get()->getLinkedUUID()); + } + + // Take them off by removing from COF. + removeItemsFromAvatar(item_ids); +} + +void LLAppearanceMgr::removeAllAttachmentsFromAvatar() +{ + if (!isAgentAvatarValid()) return; + + LLAgentWearables::llvo_vec_t objects_to_remove; + + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end();) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = attachment_iter->get(); + if (attached_object) + { + objects_to_remove.push_back(attached_object); + } + } + } + uuid_vec_t ids_to_remove; + for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_remove.begin(); + it != objects_to_remove.end(); + ++it) + { + ids_to_remove.push_back((*it)->getAttachmentItemID()); + } + removeItemsFromAvatar(ids_to_remove); +} + +class LLUpdateOnCOFLinkRemove : public LLInventoryCallback +{ +public: + LLUpdateOnCOFLinkRemove(const LLUUID& remove_item_id, LLPointer cb = NULL): + mItemID(remove_item_id), + mCB(cb) + { + } + + /* virtual */ void fire(const LLUUID& item_id) + { + // just removed cof link, "(wear)" suffix depends on presence of link, so update label + gInventory.addChangedMask(LLInventoryObserver::LABEL, mItemID); + if (mCB.notNull()) + { + mCB->fire(item_id); + } + } + +private: + LLUUID mItemID; + LLPointer mCB; +}; + +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer cb) +{ LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; igetIsLinkType() && item->getLinkedUUID() == item_id) + { + if (item->getType() == LLAssetType::AT_OBJECT) + { + // Immediate delete + remove_inventory_item(item->getUUID(), cb, true); + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + } + else + { + // Delayed delete + // Pointless to update item_id label here since link still exists and first notifyObservers + // call will restore (wear) suffix, mark for update after deletion + LLPointer cb_label = new LLUpdateOnCOFLinkRemove(item_id, cb); + remove_inventory_item(item->getUUID(), cb_label, false); + } + } + } +} + +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer cb) +{ + LLFindWearablesOfType filter_wearables_of_type(type); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryModel::item_array_t::const_iterator it; + + gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); + for (it = items.begin(); it != items.end(); ++it) + { + const LLViewerInventoryItem* item = *it; + if (item->getIsLinkType()) // we must operate on links only { - result.push_back(item_array.at(i)); + remove_inventory_item(item->getUUID(), cb); } } - return result; } -bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +void LLAppearanceMgr::updateIsDirty() { - LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); - return links.size() > 0; -} + LLUUID cof = getCOF(); + LLUUID base_outfit; -void LLAppearanceMgr::removeAllClothesFromAvatar() -{ - // Fetch worn clothes (i.e. the ones in COF). - LLInventoryModel::item_array_t clothing_items; - LLInventoryModel::cat_array_t dummy; - LLIsType is_clothing(LLAssetType::AT_CLOTHING); - gInventory.collectDescendentsIf(getCOF(), - dummy, - clothing_items, - LLInventoryModel::EXCLUDE_TRASH, - is_clothing); - uuid_vec_t item_ids; - for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); - it != clothing_items.end(); ++it) - { - item_ids.push_back((*it).get()->getLinkedUUID()); - } - - // Take them off by removing from COF. - removeItemsFromAvatar(item_ids); -} + // find base outfit link + const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink(); + LLViewerInventoryCategory* catp = NULL; + if (base_outfit_item && base_outfit_item->getIsLinkType()) + { + catp = base_outfit_item->getLinkedCategory(); + } + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + base_outfit = catp->getUUID(); + } -void LLAppearanceMgr::removeAllAttachmentsFromAvatar() -{ - if (!isAgentAvatarValid()) return; - - LLAgentWearables::llvo_vec_t objects_to_remove; - - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end();) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = attachment_iter->get(); - if (attached_object) - { - objects_to_remove.push_back(attached_object); - } - } - } - uuid_vec_t ids_to_remove; - for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_remove.begin(); - it != objects_to_remove.end(); - ++it) - { - ids_to_remove.push_back((*it)->getAttachmentItemID()); - } - removeItemsFromAvatar(ids_to_remove); -} + // Set dirty to "false" if no base outfit found to disable "Save" + // and leave only "Save As" enabled in My Outfits. + mOutfitIsDirty = false; -class LLUpdateOnCOFLinkRemove : public LLInventoryCallback -{ -public: - LLUpdateOnCOFLinkRemove(const LLUUID& remove_item_id, LLPointer cb = NULL): - mItemID(remove_item_id), - mCB(cb) - { - } - - /* virtual */ void fire(const LLUUID& item_id) - { - // just removed cof link, "(wear)" suffix depends on presence of link, so update label - gInventory.addChangedMask(LLInventoryObserver::LABEL, mItemID); - if (mCB.notNull()) - { - mCB->fire(item_id); - } - } + if (base_outfit.notNull()) + { + LLIsValidItemLink collector; -private: - LLUUID mItemID; - LLPointer mCB; -}; + LLInventoryModel::cat_array_t cof_cats; + LLInventoryModel::item_array_t cof_items; + gInventory.collectDescendentsIf(cof, cof_cats, cof_items, + LLInventoryModel::EXCLUDE_TRASH, collector); -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer cb) -{ LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::getCOF(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; igetIsLinkType() && item->getLinkedUUID() == item_id) - { - if (item->getType() == LLAssetType::AT_OBJECT) - { - // Immediate delete - remove_inventory_item(item->getUUID(), cb, true); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - } - else - { - // Delayed delete - // Pointless to update item_id label here since link still exists and first notifyObservers - // call will restore (wear) suffix, mark for update after deletion - LLPointer cb_label = new LLUpdateOnCOFLinkRemove(item_id, cb); - remove_inventory_item(item->getUUID(), cb_label, false); - } - } - } -} + LLInventoryModel::cat_array_t outfit_cats; + LLInventoryModel::item_array_t outfit_items; + gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, + LLInventoryModel::EXCLUDE_TRASH, collector); -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer cb) -{ - LLFindWearablesOfType filter_wearables_of_type(type); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryModel::item_array_t::const_iterator it; + for (U32 i = 0; i < outfit_items.size(); ++i) + { + LLViewerInventoryItem* linked_item = outfit_items.at(i)->getLinkedItem(); + if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + outfit_items.erase(outfit_items.begin() + i); + break; + } + } - gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); - for (it = items.begin(); it != items.end(); ++it) - { - const LLViewerInventoryItem* item = *it; - if (item->getIsLinkType()) // we must operate on links only - { - remove_inventory_item(item->getUUID(), cb); - } - } -} + if(outfit_items.size() != cof_items.size()) + { + LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; + // Current outfit folder should have one more item than the outfit folder. + // this one item is the link back to the outfit folder itself. + mOutfitIsDirty = true; + return; + } -void LLAppearanceMgr::updateIsDirty() -{ - LLUUID cof = getCOF(); - LLUUID base_outfit; - - // find base outfit link - const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink(); - LLViewerInventoryCategory* catp = NULL; - if (base_outfit_item && base_outfit_item->getIsLinkType()) - { - catp = base_outfit_item->getLinkedCategory(); - } - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - base_outfit = catp->getUUID(); - } - - // Set dirty to "false" if no base outfit found to disable "Save" - // and leave only "Save As" enabled in My Outfits. - mOutfitIsDirty = false; - - if (base_outfit.notNull()) - { - LLIsValidItemLink collector; - - LLInventoryModel::cat_array_t cof_cats; - LLInventoryModel::item_array_t cof_items; - gInventory.collectDescendentsIf(cof, cof_cats, cof_items, - LLInventoryModel::EXCLUDE_TRASH, collector); - - LLInventoryModel::cat_array_t outfit_cats; - LLInventoryModel::item_array_t outfit_items; - gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, - LLInventoryModel::EXCLUDE_TRASH, collector); - - for (U32 i = 0; i < outfit_items.size(); ++i) - { - LLViewerInventoryItem* linked_item = outfit_items.at(i)->getLinkedItem(); - if (linked_item != NULL && linked_item->getActualType() == LLAssetType::AT_TEXTURE) - { - outfit_items.erase(outfit_items.begin() + i); - break; - } - } - - if(outfit_items.size() != cof_items.size()) - { - LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; - // Current outfit folder should have one more item than the outfit folder. - // this one item is the link back to the outfit folder itself. - mOutfitIsDirty = true; - return; - } - - //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) - std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); - std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); - - for (U32 i = 0; i < cof_items.size(); ++i) - { - LLViewerInventoryItem *item1 = cof_items.at(i); - LLViewerInventoryItem *item2 = outfit_items.at(i); - - if (item1->getLinkedUUID() != item2->getLinkedUUID() || - item1->getName() != item2->getName() || - item1->getActualDescription() != item2->getActualDescription()) - { - if (item1->getLinkedUUID() != item2->getLinkedUUID()) - { - LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; - } - else - { - if (item1->getName() != item2->getName()) - { - LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; - } - if (item1->getActualDescription() != item2->getActualDescription()) - { - LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() - << " " << item2->getActualDescription() - << " names " << item1->getName() << " " << item2->getName() << LL_ENDL; - } - } - mOutfitIsDirty = true; - return; - } - } - } - llassert(!mOutfitIsDirty); - LL_DEBUGS("Avatar") << "clean" << LL_ENDL; + //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) + std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); + std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); + + for (U32 i = 0; i < cof_items.size(); ++i) + { + LLViewerInventoryItem *item1 = cof_items.at(i); + LLViewerInventoryItem *item2 = outfit_items.at(i); + + if (item1->getLinkedUUID() != item2->getLinkedUUID() || + item1->getName() != item2->getName() || + item1->getActualDescription() != item2->getActualDescription()) + { + if (item1->getLinkedUUID() != item2->getLinkedUUID()) + { + LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; + } + else + { + if (item1->getName() != item2->getName()) + { + LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + if (item1->getActualDescription() != item2->getActualDescription()) + { + LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() + << " " << item2->getActualDescription() + << " names " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + } + mOutfitIsDirty = true; + return; + } + } + } + llassert(!mOutfitIsDirty); + LL_DEBUGS("Avatar") << "clean" << LL_ENDL; } // *HACK: Must match name in Library or agent inventory @@ -3316,152 +3316,152 @@ const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; void LLAppearanceMgr::copyLibraryGestures() { - LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; - - // Copy gestures - LLUUID lib_gesture_cat_id = - gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE); - if (lib_gesture_cat_id.isNull()) - { - LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; - } - LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); - - std::vector gesture_folders_to_copy; - gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); - gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); - - for(std::vector::iterator it = gesture_folders_to_copy.begin(); - it != gesture_folders_to_copy.end(); - ++it) - { - std::string& folder_name = *it; - - LLPointer cb(NULL); - - // After copying gestures, activate Common, Other, plus - // Male and/or Female, depending upon the initial outfit gender. - ESex gender = gAgentAvatarp->getSex(); - - std::string activate_male_gestures; - std::string activate_female_gestures; - switch (gender) { - case SEX_MALE: - activate_male_gestures = MALE_GESTURES_FOLDER; - break; - case SEX_FEMALE: - activate_female_gestures = FEMALE_GESTURES_FOLDER; - break; - case SEX_BOTH: - activate_male_gestures = MALE_GESTURES_FOLDER; - activate_female_gestures = FEMALE_GESTURES_FOLDER; - break; - } - - if (folder_name == activate_male_gestures || - folder_name == activate_female_gestures || - folder_name == COMMON_GESTURES_FOLDER || - folder_name == OTHER_GESTURES_FOLDER) - { - cb = new LLBoostFuncInventoryCallback(activate_gesture_cb); - } - - LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); - if (cat_id.isNull()) - { - LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL; - } - else - { - LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; - callAfterCategoryFetch(cat_id, - boost::bind(&LLAppearanceMgr::shallowCopyCategory, - &LLAppearanceMgr::instance(), - cat_id, dst_id, cb)); - } - } + LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; + + // Copy gestures + LLUUID lib_gesture_cat_id = + gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE); + if (lib_gesture_cat_id.isNull()) + { + LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; + } + LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + + std::vector gesture_folders_to_copy; + gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); + + for(std::vector::iterator it = gesture_folders_to_copy.begin(); + it != gesture_folders_to_copy.end(); + ++it) + { + std::string& folder_name = *it; + + LLPointer cb(NULL); + + // After copying gestures, activate Common, Other, plus + // Male and/or Female, depending upon the initial outfit gender. + ESex gender = gAgentAvatarp->getSex(); + + std::string activate_male_gestures; + std::string activate_female_gestures; + switch (gender) { + case SEX_MALE: + activate_male_gestures = MALE_GESTURES_FOLDER; + break; + case SEX_FEMALE: + activate_female_gestures = FEMALE_GESTURES_FOLDER; + break; + case SEX_BOTH: + activate_male_gestures = MALE_GESTURES_FOLDER; + activate_female_gestures = FEMALE_GESTURES_FOLDER; + break; + } + + if (folder_name == activate_male_gestures || + folder_name == activate_female_gestures || + folder_name == COMMON_GESTURES_FOLDER || + folder_name == OTHER_GESTURES_FOLDER) + { + cb = new LLBoostFuncInventoryCallback(activate_gesture_cb); + } + + LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); + if (cat_id.isNull()) + { + LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; + callAfterCategoryFetch(cat_id, + boost::bind(&LLAppearanceMgr::shallowCopyCategory, + &LLAppearanceMgr::instance(), + cat_id, dst_id, cb)); + } + } } // Handler for anything that's deferred until avatar de-clouds. void LLAppearanceMgr::onFirstFullyVisible() { - gAgentAvatarp->outputRezTiming("Avatar fully loaded"); - gAgentAvatarp->reportAvatarRezTime(); - gAgentAvatarp->debugAvatarVisible(); + gAgentAvatarp->outputRezTiming("Avatar fully loaded"); + gAgentAvatarp->reportAvatarRezTime(); + gAgentAvatarp->debugAvatarVisible(); - // If this is the first time we've ever logged in, - // then copy default gestures from the library. - if (gAgent.isFirstLogin()) { - copyLibraryGestures(); - } + // If this is the first time we've ever logged in, + // then copy default gestures from the library. + if (gAgent.isFirstLogin()) { + copyLibraryGestures(); + } } // update "dirty" state - defined outside class to allow for calling // after appearance mgr instance has been destroyed. void appearance_mgr_update_dirty_state() { - if (LLAppearanceMgr::instanceExists()) - { - LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); - LLUUID image_id = app_mgr.getOutfitImage(); - if(image_id.notNull()) - { - LLPointer cb = NULL; - link_inventory_object(app_mgr.getBaseOutfitUUID(), image_id, cb); - } + if (LLAppearanceMgr::instanceExists()) + { + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + LLUUID image_id = app_mgr.getOutfitImage(); + if(image_id.notNull()) + { + LLPointer cb = NULL; + link_inventory_object(app_mgr.getBaseOutfitUUID(), image_id, cb); + } - LLAppearanceMgr::getInstance()->updateIsDirty(); - LLAppearanceMgr::getInstance()->setOutfitLocked(false); - gAgentWearables.notifyLoadingFinished(); - } + LLAppearanceMgr::getInstance()->updateIsDirty(); + LLAppearanceMgr::getInstance()->setOutfitLocked(false); + gAgentWearables.notifyLoadingFinished(); + } } void update_base_outfit_after_ordering() { - LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); - app_mgr.setOutfitImage(LLUUID()); - LLInventoryModel::cat_array_t sub_cat_array; - LLInventoryModel::item_array_t outfit_item_array; - gInventory.collectDescendents(app_mgr.getBaseOutfitUUID(), - sub_cat_array, - outfit_item_array, - LLInventoryModel::EXCLUDE_TRASH); - for (LLViewerInventoryItem* outfit_item : outfit_item_array) - { - LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); - if (linked_item != NULL) - { - if (linked_item->getActualType() == LLAssetType::AT_TEXTURE) - { - app_mgr.setOutfitImage(linked_item->getLinkedUUID()); - if (linked_item->getName() == LLAppearanceMgr::sExpectedTextureName) - { - // Images with "appropriate" name take priority - break; - } - } - } - else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE) - { - app_mgr.setOutfitImage(outfit_item->getUUID()); - if (outfit_item->getName() == LLAppearanceMgr::sExpectedTextureName) - { - // Images with "appropriate" name take priority - break; - } - } - } - - LLPointer dirty_state_updater = - new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); - - //COF contains only links so we copy to the Base Outfit only links - const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); - bool copy_folder_links = false; - app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + app_mgr.setOutfitImage(LLUUID()); + LLInventoryModel::cat_array_t sub_cat_array; + LLInventoryModel::item_array_t outfit_item_array; + gInventory.collectDescendents(app_mgr.getBaseOutfitUUID(), + sub_cat_array, + outfit_item_array, + LLInventoryModel::EXCLUDE_TRASH); + for (LLViewerInventoryItem* outfit_item : outfit_item_array) + { + LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); + if (linked_item != NULL) + { + if (linked_item->getActualType() == LLAssetType::AT_TEXTURE) + { + app_mgr.setOutfitImage(linked_item->getLinkedUUID()); + if (linked_item->getName() == LLAppearanceMgr::sExpectedTextureName) + { + // Images with "appropriate" name take priority + break; + } + } + } + else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE) + { + app_mgr.setOutfitImage(outfit_item->getUUID()); + if (outfit_item->getName() == LLAppearanceMgr::sExpectedTextureName) + { + // Images with "appropriate" name take priority + break; + } + } + } + + LLPointer dirty_state_updater = + new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); + + //COF contains only links so we copy to the Base Outfit only links + const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); + bool copy_folder_links = false; + app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); if (base_outfit_id.notNull()) { @@ -3513,245 +3513,245 @@ void update_base_outfit_after_ordering() // to match the current COF. Fails if no current base outfit is set. bool LLAppearanceMgr::updateBaseOutfit() { - if (isOutfitLocked()) - { - // don't allow modify locked outfit - llassert(!isOutfitLocked()); - return false; - } + if (isOutfitLocked()) + { + // don't allow modify locked outfit + llassert(!isOutfitLocked()); + return false; + } - setOutfitLocked(true); + setOutfitLocked(true); - gAgentWearables.notifyLoadingStarted(); + gAgentWearables.notifyLoadingStarted(); - const LLUUID base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.isNull()) return false; - LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; + const LLUUID base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.isNull()) return false; + LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; - LLPointer cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); - // Really shouldn't be needed unless there's a race condition - - // updateAppearanceFromCOF() already calls updateClothingOrderingInfo. - updateClothingOrderingInfo(LLUUID::null, cb); + LLPointer cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); + // Really shouldn't be needed unless there's a race condition - + // updateAppearanceFromCOF() already calls updateClothingOrderingInfo. + updateClothingOrderingInfo(LLUUID::null, cb); - return true; + return true; } void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) { - items_by_type.resize(LLWearableType::WT_COUNT); - if (items.empty()) return; - - for (S32 i=0; iisWearableType()) - continue; - LLWearableType::EType type = item->getWearableType(); - if(type < 0 || type >= LLWearableType::WT_COUNT) - { - LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; - continue; - } - items_by_type[type].push_back(item); - } + items_by_type.resize(LLWearableType::WT_COUNT); + if (items.empty()) return; + + for (S32 i=0; iisWearableType()) + continue; + LLWearableType::EType type = item->getWearableType(); + if(type < 0 || type >= LLWearableType::WT_COUNT) + { + LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; + continue; + } + items_by_type[type].push_back(item); + } } std::string build_order_string(LLWearableType::EType type, U32 i) { - std::ostringstream order_num; - order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; - return order_num.str(); + std::ostringstream order_num; + order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; + return order_num.str(); } struct WearablesOrderComparator { - LOG_CLASS(WearablesOrderComparator); - WearablesOrderComparator(const LLWearableType::EType type) - { - mControlSize = build_order_string(type, 0).size(); - }; - - bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) - { - const std::string& desc1 = item1->getActualDescription(); - const std::string& desc2 = item2->getActualDescription(); - - bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); - bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); - - if (item1_valid && item2_valid) - return desc1 < desc2; - - //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, - //items with ordering information but not for the associated wearables type - if (!item1_valid && item2_valid) - return false; - else if (item1_valid && !item2_valid) - return true; - - return item1->getName() < item2->getName(); - } - - U32 mControlSize; + LOG_CLASS(WearablesOrderComparator); + WearablesOrderComparator(const LLWearableType::EType type) + { + mControlSize = build_order_string(type, 0).size(); + }; + + bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) + { + const std::string& desc1 = item1->getActualDescription(); + const std::string& desc2 = item2->getActualDescription(); + + bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); + bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); + + if (item1_valid && item2_valid) + return desc1 < desc2; + + //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, + //items with ordering information but not for the associated wearables type + if (!item1_valid && item2_valid) + return false; + else if (item1_valid && !item2_valid) + return true; + + return item1->getName() < item2->getName(); + } + + U32 mControlSize; }; void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, - desc_map_t& desc_map) -{ - wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); - divvyWearablesByType(wear_items, items_by_type); - - for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) - { - U32 size = items_by_type[type].size(); - if (!size) continue; - - //sinking down invalid items which need reordering - std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); - - //requesting updates only for those links which don't have "valid" descriptions - for (U32 i = 0; i < size; i++) - { - LLViewerInventoryItem* item = items_by_type[type][i]; - if (!item) continue; - - std::string new_order_str = build_order_string((LLWearableType::EType)type, i); - if (new_order_str == item->getActualDescription()) continue; - - desc_map[item->getUUID()] = new_order_str; - } - } + desc_map_t& desc_map) +{ + wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); + divvyWearablesByType(wear_items, items_by_type); + + for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) + { + U32 size = items_by_type[type].size(); + if (!size) continue; + + //sinking down invalid items which need reordering + std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); + + //requesting updates only for those links which don't have "valid" descriptions + for (U32 i = 0; i < size; i++) + { + LLViewerInventoryItem* item = items_by_type[type][i]; + if (!item) continue; + + std::string new_order_str = build_order_string((LLWearableType::EType)type, i); + if (new_order_str == item->getActualDescription()) continue; + + desc_map[item->getUUID()] = new_order_str; + } + } } bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id) { - // COF is processed if cat_id is not specified - if (cat_id.isNull()) - { - cat_id = getCOF(); - } - - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); - - // Identify items for which desc needs to change. - desc_map_t desc_map; - getWearableOrderingDescUpdates(wear_items, desc_map); - - for (desc_map_t::const_iterator it = desc_map.begin(); - it != desc_map.end(); ++it) - { - const LLUUID& item_id = it->first; - const std::string& new_order_str = it->second; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_WARNS() << "Order validation fails: " << item->getName() - << " needs to update desc to: " << new_order_str - << " (from: " << item->getActualDescription() << ")" << LL_ENDL; - } - - return desc_map.size() == 0; + // COF is processed if cat_id is not specified + if (cat_id.isNull()) + { + cat_id = getCOF(); + } + + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) + { + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_WARNS() << "Order validation fails: " << item->getName() + << " needs to update desc to: " << new_order_str + << " (from: " << item->getActualDescription() << ")" << LL_ENDL; + } + + return desc_map.size() == 0; } void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, - LLPointer cb) + LLPointer cb) { - // COF is processed if cat_id is not specified - if (cat_id.isNull()) - { - cat_id = getCOF(); - } + // COF is processed if cat_id is not specified + if (cat_id.isNull()) + { + cat_id = getCOF(); + } - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); - // Identify items for which desc needs to change. - desc_map_t desc_map; - getWearableOrderingDescUpdates(wear_items, desc_map); + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) + { + LLSD updates; + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + updates["desc"] = new_order_str; + update_inventory_item(item_id,updates,cb); + } - for (desc_map_t::const_iterator it = desc_map.begin(); - it != desc_map.end(); ++it) - { - LLSD updates; - const LLUUID& item_id = it->first; - const std::string& new_order_str = it->second; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str - << " (was: " << item->getActualDescription() << ")" << LL_ENDL; - updates["desc"] = new_order_str; - update_inventory_item(item_id,updates,cb); - } - } LLSD LLAppearanceMgr::dumpCOF() const { - LLSD links = LLSD::emptyArray(); - LLMD5 md5; - - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; igetUUID()); - md5.update((unsigned char*)item_id.mData, 16); - item["description"] = inv_item->getActualDescription(); - md5.update(inv_item->getActualDescription()); - item["asset_type"] = inv_item->getActualType(); - LLUUID linked_id(inv_item->getLinkedUUID()); - item["linked_id"] = linked_id; - md5.update((unsigned char*)linked_id.mData, 16); - - if (LLAssetType::AT_LINK == inv_item->getActualType()) - { - const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem(); - if (NULL == linked_item) - { - LL_WARNS() << "Broken link for item '" << inv_item->getName() - << "' (" << inv_item->getUUID() - << ") during requestServerAppearanceUpdate" << LL_ENDL; - continue; - } - // Some assets may be 'hidden' and show up as null in the viewer. - //if (linked_item->getAssetUUID().isNull()) - //{ - // LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName() - // << "' (" << inv_item->getUUID() - // << ") during requestServerAppearanceUpdate" << LL_ENDL; - // continue; - //} - LLUUID linked_asset_id(linked_item->getAssetUUID()); - md5.update((unsigned char*)linked_asset_id.mData, 16); - U32 flags = linked_item->getFlags(); - md5.update(std::to_string(flags)); - } - else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) - { - LL_WARNS() << "Non-link item '" << inv_item->getName() - << "' (" << inv_item->getUUID() - << ") type " << (S32) inv_item->getActualType() - << " during requestServerAppearanceUpdate" << LL_ENDL; - continue; - } - links.append(item); - } - LLSD result = LLSD::emptyMap(); - result["cof_contents"] = links; - char cof_md5sum[MD5HEX_STR_SIZE]; - md5.finalize(); - md5.hex_digest(cof_md5sum); - result["cof_md5sum"] = std::string(cof_md5sum); - return result; + LLSD links = LLSD::emptyArray(); + LLMD5 md5; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; igetUUID()); + md5.update((unsigned char*)item_id.mData, 16); + item["description"] = inv_item->getActualDescription(); + md5.update(inv_item->getActualDescription()); + item["asset_type"] = inv_item->getActualType(); + LLUUID linked_id(inv_item->getLinkedUUID()); + item["linked_id"] = linked_id; + md5.update((unsigned char*)linked_id.mData, 16); + + if (LLAssetType::AT_LINK == inv_item->getActualType()) + { + const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem(); + if (NULL == linked_item) + { + LL_WARNS() << "Broken link for item '" << inv_item->getName() + << "' (" << inv_item->getUUID() + << ") during requestServerAppearanceUpdate" << LL_ENDL; + continue; + } + // Some assets may be 'hidden' and show up as null in the viewer. + //if (linked_item->getAssetUUID().isNull()) + //{ + // LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName() + // << "' (" << inv_item->getUUID() + // << ") during requestServerAppearanceUpdate" << LL_ENDL; + // continue; + //} + LLUUID linked_asset_id(linked_item->getAssetUUID()); + md5.update((unsigned char*)linked_asset_id.mData, 16); + U32 flags = linked_item->getFlags(); + md5.update(std::to_string(flags)); + } + else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) + { + LL_WARNS() << "Non-link item '" << inv_item->getName() + << "' (" << inv_item->getUUID() + << ") type " << (S32) inv_item->getActualType() + << " during requestServerAppearanceUpdate" << LL_ENDL; + continue; + } + links.append(item); + } + LLSD result = LLSD::emptyMap(); + result["cof_contents"] = links; + char cof_md5sum[MD5HEX_STR_SIZE]; + md5.finalize(); + md5.hex_digest(cof_md5sum); + result["cof_md5sum"] = std::string(cof_md5sum); + return result; } // static @@ -3819,7 +3819,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd bool bRetry; do { - // If we have already received an update for this or higher cof version, + // If we have already received an update for this or higher cof version, // put a warning in the log and cancel the request. S32 cofVersion = getCOFVersion(); S32 lastRcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; @@ -3891,9 +3891,9 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd std::string message = (result.has("error")) ? result["error"].asString() : status.toString(); LL_WARNS("Avatar") << "Appearance Failure. server responded with \"" << message << "\"" << LL_ENDL; - // We may have requested a bake for a stale COF (especially if the inventory - // is still updating. If that is the case re send the request with the - // corrected COF version. (This may also be the case if the viewer is running + // We may have requested a bake for a stale COF (especially if the inventory + // is still updating. If that is the case re send the request with the + // corrected COF version. (This may also be the case if the viewer is running // on multiple machines. if (result.has("expected")) { @@ -3917,7 +3917,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LL_WARNS("Avatar") << "Bake retry #" << retryCount << " in " << timeout << " seconds." << LL_ENDL; - llcoro::suspendUntilTimeout(timeout); + llcoro::suspendUntilTimeout(timeout); if (LLApp::isExiting()) { return; @@ -4028,81 +4028,81 @@ void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content) std::string LLAppearanceMgr::getAppearanceServiceURL() const { - if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) - { - return mAppearanceServiceURL; - } - return gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride"); + if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) + { + return mAppearanceServiceURL; + } + return gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride"); } void show_created_outfit(LLUUID& folder_id, bool show_panel = true) { - if (!LLApp::isRunning()) - { - LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; - return; - } - - LL_DEBUGS("Avatar") << "called" << LL_ENDL; - LLSD key; - - //EXT-7727. For new accounts inventory callback is created during login process - // and may be processed after login process is finished - if (show_panel) - { - LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; - LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); - - } - LLOutfitsList *outfits_list = - dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); - if (outfits_list) - { - outfits_list->setSelectedOutfitByUUID(folder_id); - } - - LLAppearanceMgr::getInstance()->updateIsDirty(); - gAgentWearables.notifyLoadingFinished(); // New outfit is saved. - LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); - - // For SSB, need to update appearance after we add a base outfit - // link, since, the COF version has changed. There is a race - // condition in initial outfit setup which can lead to rez - // failures - SH-3860. - LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; - LLPointer cb = new LLUpdateAppearanceOnDestroy; - LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); + if (!LLApp::isRunning()) + { + LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; + return; + } + + LL_DEBUGS("Avatar") << "called" << LL_ENDL; + LLSD key; + + //EXT-7727. For new accounts inventory callback is created during login process + // and may be processed after login process is finished + if (show_panel) + { + LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; + LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); + + } + LLOutfitsList *outfits_list = + dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); + if (outfits_list) + { + outfits_list->setSelectedOutfitByUUID(folder_id); + } + + LLAppearanceMgr::getInstance()->updateIsDirty(); + gAgentWearables.notifyLoadingFinished(); // New outfit is saved. + LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + + // For SSB, need to update appearance after we add a base outfit + // link, since, the COF version has changed. There is a race + // condition in initial outfit setup which can lead to rez + // failures - SH-3860. + LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; + LLPointer cb = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); } void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel) { - LLPointer cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, - boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); - updateClothingOrderingInfo(LLUUID::null, cb); + LLPointer cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); + updateClothingOrderingInfo(LLUUID::null, cb); } void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel) { - LLPointer cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, - boost::bind(show_created_outfit,folder_id,show_panel)); - bool copy_folder_links = false; - slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); + LLPointer cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(show_created_outfit,folder_id,show_panel)); + bool copy_folder_links = false; + slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); } void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) { - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) return; - LLUIUsage::instance().logCommand("Avatar.CreateNewOutfit"); + LLUIUsage::instance().logCommand("Avatar.CreateNewOutfit"); - LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; + LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; - gAgentWearables.notifyLoadingStarted(); + gAgentWearables.notifyLoadingStarted(); - // First, make a folder in the My Outfits directory. - const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + // First, make a folder in the My Outfits directory. + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); gInventory.createNewCategory( parent_id, @@ -4116,218 +4116,218 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo void LLAppearanceMgr::wearBaseOutfit() { - const LLUUID& base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.isNull()) return; - - updateCOF(base_outfit_id); + const LLUUID& base_outfit_id = getBaseOutfitUUID(); + if (base_outfit_id.isNull()) return; + + updateCOF(base_outfit_id); } void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) { - LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL; - LLUIUsage::instance().logCommand("Avatar.RemoveItem"); - - if (ids_to_remove.empty()) - { - LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; - return; - } - LLPointer cb = new LLUpdateAppearanceOnDestroy; - for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) - { - const LLUUID& id_to_remove = *it; - const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); - LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); - if (item && item->getType() == LLAssetType::AT_OBJECT) - { - LL_DEBUGS("Avatar") << "ATT removing attachment " << item->getName() << " id " << item->getUUID() << LL_ENDL; - } - if (item && item->getType() == LLAssetType::AT_BODYPART) - { - continue; - } - removeCOFItemLinks(linked_item_id, cb); - addDoomedTempAttachment(linked_item_id); - } + LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL; + LLUIUsage::instance().logCommand("Avatar.RemoveItem"); + + if (ids_to_remove.empty()) + { + LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; + return; + } + LLPointer cb = new LLUpdateAppearanceOnDestroy; + for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) + { + const LLUUID& id_to_remove = *it; + const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); + LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); + if (item && item->getType() == LLAssetType::AT_OBJECT) + { + LL_DEBUGS("Avatar") << "ATT removing attachment " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (item && item->getType() == LLAssetType::AT_BODYPART) + { + continue; + } + removeCOFItemLinks(linked_item_id, cb); + addDoomedTempAttachment(linked_item_id); + } } void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) { - uuid_vec_t ids_to_remove; - ids_to_remove.push_back(id_to_remove); - removeItemsFromAvatar(ids_to_remove); + uuid_vec_t ids_to_remove; + ids_to_remove.push_back(id_to_remove); + removeItemsFromAvatar(ids_to_remove); } // Adds the given item ID to mDoomedTempAttachmentIDs iff it's a temp attachment void LLAppearanceMgr::addDoomedTempAttachment(const LLUUID& id_to_remove) { - LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove); - if (attachmentp && - attachmentp->isTempAttachment()) - { // If this is a temp attachment and we want to remove it, record the ID - // so it will be deleted when attachments are synced up with COF - mDoomedTempAttachmentIDs.insert(id_to_remove); - //LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL; - } + LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove); + if (attachmentp && + attachmentp->isTempAttachment()) + { // If this is a temp attachment and we want to remove it, record the ID + // so it will be deleted when attachments are synced up with COF + mDoomedTempAttachmentIDs.insert(id_to_remove); + //LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL; + } } // Find AND REMOVES the given UUID from mDoomedTempAttachmentIDs bool LLAppearanceMgr::shouldRemoveTempAttachment(const LLUUID& item_id) { - doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id); - if (iter != mDoomedTempAttachmentIDs.end()) - { - mDoomedTempAttachmentIDs.erase(iter); - return true; - } - return false; + doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id); + if (iter != mDoomedTempAttachmentIDs.end()) + { + mDoomedTempAttachmentIDs.erase(iter); + return true; + } + return false; } bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) { - if (!item || !item->isWearableType()) return false; - if (item->getType() != LLAssetType::AT_CLOTHING) return false; - if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; + if (!item || !item->isWearableType()) return false; + if (item->getType() != LLAssetType::AT_CLOTHING) return false; + if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; + + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); + gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); + if (items.empty()) return false; - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); - gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); - if (items.empty()) return false; + // We assume that the items have valid descriptions. + std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); - // We assume that the items have valid descriptions. - std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); + if (closer_to_body && items.front() == item) return false; + if (!closer_to_body && items.back() == item) return false; - if (closer_to_body && items.front() == item) return false; - if (!closer_to_body && items.back() == item) return false; - - LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); - if (items.end() == it) return false; + LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); + if (items.end() == it) return false; - //swapping descriptions - closer_to_body ? --it : ++it; - LLViewerInventoryItem* swap_item = *it; - if (!swap_item) return false; - std::string tmp = swap_item->getActualDescription(); - swap_item->setDescription(item->getActualDescription()); - item->setDescription(tmp); + //swapping descriptions + closer_to_body ? --it : ++it; + LLViewerInventoryItem* swap_item = *it; + if (!swap_item) return false; + std::string tmp = swap_item->getActualDescription(); + swap_item->setDescription(item->getActualDescription()); + item->setDescription(tmp); - // LL_DEBUGS("Inventory") << "swap, item " - // << ll_pretty_print_sd(item->asLLSD()) - // << " swap_item " - // << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; + // LL_DEBUGS("Inventory") << "swap, item " + // << ll_pretty_print_sd(item->asLLSD()) + // << " swap_item " + // << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; - // FIXME switch to use AISv3 where supported. - //items need to be updated on a dataserver - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); + // FIXME switch to use AISv3 where supported. + //items need to be updated on a dataserver + item->setComplete(TRUE); + item->updateServer(FALSE); + gInventory.updateItem(item); - swap_item->setComplete(TRUE); - swap_item->updateServer(FALSE); - gInventory.updateItem(swap_item); + swap_item->setComplete(TRUE); + swap_item->updateServer(FALSE); + gInventory.updateItem(swap_item); - //to cause appearance of the agent to be updated - bool result = false; - if ((result = gAgentWearables.moveWearable(item, closer_to_body))) - { - gAgentAvatarp->wearableUpdated(item->getWearableType()); - } + //to cause appearance of the agent to be updated + bool result = false; + if ((result = gAgentWearables.moveWearable(item, closer_to_body))) + { + gAgentAvatarp->wearableUpdated(item->getWearableType()); + } - setOutfitDirty(true); + setOutfitDirty(true); - //*TODO do we need to notify observers here in such a way? - gInventory.notifyObservers(); + //*TODO do we need to notify observers here in such a way? + gInventory.notifyObservers(); - return result; + return result; } //static void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items) { - if (items.size() < 2) return; + if (items.size() < 2) return; - std::sort(items.begin(), items.end(), sort_by_actual_description); + std::sort(items.begin(), items.end(), sort_by_actual_description); } //#define DUMP_CAT_VERBOSE void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); #ifdef DUMP_CAT_VERBOSE - LL_INFOS() << LL_ENDL; - LL_INFOS() << str << LL_ENDL; - S32 hitcount = 0; - for(S32 i=0; igetName() <getName() <getLinkedItem() : NULL; - LLUUID asset_id; - if (linked_item) - { - asset_id = linked_item->getAssetUUID(); - } - LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; - } + for (S32 i=0; igetLinkedItem() : NULL; + LLUUID asset_id; + if (linked_item) + { + asset_id = linked_item->getAssetUUID(); + } + LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; + } } bool LLAppearanceMgr::mActive = true; LLAppearanceMgr::LLAppearanceMgr(): - mAttachmentInvLinkEnabled(false), - mOutfitIsDirty(false), - mOutfitLocked(false), - mInFlightTimer(), - mIsInUpdateAppearanceFromCOF(false), + mAttachmentInvLinkEnabled(false), + mOutfitIsDirty(false), + mOutfitLocked(false), + mInFlightTimer(), + mIsInUpdateAppearanceFromCOF(false), mOutstandingAppearanceBakeRequest(false), mRerequestAppearanceBake(false) { - LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); - // unlock outfit on save operation completed - outfit_observer.addCOFSavedCallback(boost::bind( - &LLAppearanceMgr::setOutfitLocked, this, false)); + LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); + // unlock outfit on save operation completed + outfit_observer.addCOFSavedCallback(boost::bind( + &LLAppearanceMgr::setOutfitLocked, this, false)); - mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( - "OutfitOperationsTimeout"))); + mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( + "OutfitOperationsTimeout"))); - gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); - gIdleCallbacks.addFunction(&LLAppearanceMgr::onIdle, NULL); //sheduling appearance update requests + gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); + gIdleCallbacks.addFunction(&LLAppearanceMgr::onIdle, NULL); //sheduling appearance update requests } LLAppearanceMgr::~LLAppearanceMgr() { - mActive = false; + mActive = false; } void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) { - LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; - mAttachmentInvLinkEnabled = val; + LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; + mAttachmentInvLinkEnabled = val; } boost::signals2::connection LLAppearanceMgr::setAttachmentsChangedCallback(attachments_changed_callback_t cb) { - return mAttachmentsChangeSignal.connect(cb); + return mAttachmentsChangeSignal.connect(cb); } void dumpAttachmentSet(const std::set& atts, const std::string& msg) @@ -4349,101 +4349,101 @@ void dumpAttachmentSet(const std::set& atts, const std::string& msg) void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) { - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_DEBUGS("Avatar") << "ATT registering attachment " - << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT registering attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - LLAttachmentsMgr::instance().onAttachmentArrived(item_id); + LLAttachmentsMgr::instance().onAttachmentArrived(item_id); - mAttachmentsChangeSignal(); + mAttachmentsChangeSignal(); } void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) { - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LL_DEBUGS("Avatar") << "ATT unregistering attachment " - << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT unregistering attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); LLAttachmentsMgr::instance().onDetachCompleted(item_id); - if (mAttachmentInvLinkEnabled && isLinkedInCOF(item_id)) - { - LL_DEBUGS("Avatar") << "ATT removing COF link for attachment " - << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; - LLAppearanceMgr::removeCOFItemLinks(item_id); - } - else - { - //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; - } + if (mAttachmentInvLinkEnabled && isLinkedInCOF(item_id)) + { + LL_DEBUGS("Avatar") << "ATT removing COF link for attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + LLAppearanceMgr::removeCOFItemLinks(item_id); + } + else + { + //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; + } - mAttachmentsChangeSignal(); + mAttachmentsChangeSignal(); } BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const { - const LLUUID& cof = getCOF(); - if (obj_id == cof) - return TRUE; - const LLInventoryObject* obj = gInventory.getObject(obj_id); - if (obj && obj->getParentUUID() == cof) - return TRUE; - return FALSE; + const LLUUID& cof = getCOF(); + if (obj_id == cof) + return TRUE; + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == cof) + return TRUE; + return FALSE; } BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const { - if (!getIsInCOF(obj_id)) return FALSE; + if (!getIsInCOF(obj_id)) return FALSE; - // If a non-link somehow ended up in COF, allow deletion. - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (obj && !obj->getIsLinkType()) - { - return FALSE; - } + // If a non-link somehow ended up in COF, allow deletion. + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && !obj->getIsLinkType()) + { + return FALSE; + } - // For now, don't allow direct deletion from the COF. Instead, force users - // to choose "Detach" or "Take Off". - return TRUE; + // For now, don't allow direct deletion from the COF. Instead, force users + // to choose "Detach" or "Take Off". + return TRUE; } class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver { public: - CallAfterCategoryFetchStage2(const uuid_vec_t& ids, - nullary_func_t callable) : - LLInventoryFetchItemsObserver(ids), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage2() - { - } - virtual void done() - { - LL_INFOS() << this << " done with incomplete " << mIncomplete.size() - << " complete " << mComplete.size() << " calling callable" << LL_ENDL; - - gInventory.removeObserver(this); - doOnIdleOneTime(mCallable); - delete this; - } + CallAfterCategoryFetchStage2(const uuid_vec_t& ids, + nullary_func_t callable) : + LLInventoryFetchItemsObserver(ids), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage2() + { + } + virtual void done() + { + LL_INFOS() << this << " done with incomplete " << mIncomplete.size() + << " complete " << mComplete.size() << " calling callable" << LL_ENDL; + + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); + delete this; + } protected: - nullary_func_t mCallable; + nullary_func_t mCallable; }; class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver { public: - CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : - LLInventoryFetchDescendentsObserver(cat_id), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage1() - { - } + CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : + LLInventoryFetchDescendentsObserver(cat_id), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage1() + { + } /*virtual*/ void startFetch() { bool ais3 = AISAPI::isAvailable(); @@ -4458,8 +4458,8 @@ public: // as result fetch won't start and folder will potentially get stuck as // incomplete in observer. // Likely either both should use only version or both should check descendants. - cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. - mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. + cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. + mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. } else if (!isCategoryComplete(cat)) { @@ -4511,8 +4511,8 @@ public: } } } - virtual void done() - { + virtual void done() + { if (mComplete.size() <= 0) { // Ex: timeout @@ -4524,54 +4524,54 @@ public: return; } - // What we do here is get the complete information on the - // items in the requested category, and set up an observer - // that will wait for that to happen. + // What we do here is get the complete information on the + // items in the requested category, and set up an observer + // that will wait for that to happen. LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(mComplete.front(), cats, items); - S32 count = items->size(); - if(!count) - { - LL_WARNS() << "Nothing fetched in category " << mComplete.front() - << LL_ENDL; - gInventory.removeObserver(this); - doOnIdleOneTime(mCallable); + S32 count = items->size(); + if(!count) + { + LL_WARNS() << "Nothing fetched in category " << mComplete.front() + << LL_ENDL; + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); - delete this; - return; - } + delete this; + return; + } LLViewerInventoryCategory* cat = gInventory.getCategory(mComplete.front()); S32 version = cat ? cat->getVersion() : -2; - LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL; - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) - { - ids.push_back(items->at(i)->getUUID()); - } - - gInventory.removeObserver(this); - - // do the fetch - CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); - stage2->startFetch(); - if(stage2->isFinished()) - { - // everything is already here - call done. - stage2->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(stage2); - } - delete this; - } + LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL; + uuid_vec_t ids; + for(S32 i = 0; i < count; ++i) + { + ids.push_back(items->at(i)->getUUID()); + } + + gInventory.removeObserver(this); + + // do the fetch + CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); + stage2->startFetch(); + if(stage2->isFinished()) + { + // everything is already here - call done. + stage2->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(stage2); + } + delete this; + } protected: - nullary_func_t mCallable; + nullary_func_t mCallable; }; void callAfterCOFFetch(nullary_func_t cb) @@ -4621,7 +4621,7 @@ void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb) LL_WARNS() << "AIS API v3 not available, can't use AISAPI::FetchCOF" << LL_ENDL; callAfterCategoryFetch(cat_id, cb); } - + } void add_wearable_type_counts(const uuid_vec_t& ids, @@ -4673,7 +4673,7 @@ void wear_multiple(const uuid_vec_t& ids, bool replace) { cb = new LLUpdateAppearanceOnDestroy; } - LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb); + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb); } // SLapp for easy-wearing of a stock (library) avatar @@ -4681,50 +4681,50 @@ void wear_multiple(const uuid_vec_t& ids, bool replace) class LLWearFolderHandler : public LLCommandHandler { public: - // not allowed from outside the app - LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } + // not allowed from outside the app + LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& tokens, + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) - { - LLSD::UUID folder_uuid; - - if (folder_uuid.isNull() && query_map.has("folder_name")) - { - std::string outfit_folder_name = query_map["folder_name"]; - folder_uuid = findDescendentCategoryIDByName( - gInventory.getLibraryRootFolderID(), - outfit_folder_name); - } - if (folder_uuid.isNull() && query_map.has("folder_id")) - { - folder_uuid = query_map["folder_id"].asUUID(); - } - - if (folder_uuid.notNull()) - { - LLPointer category = new LLInventoryCategory(folder_uuid, - LLUUID::null, - LLFolderType::FT_CLOTHING, - "Quick Appearance"); - if ( gInventory.getCategory( folder_uuid ) != NULL ) - { - // Assume this is coming from the predefined avatars web floater - LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance"); - LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); - - // *TODOw: This may not be necessary if initial outfit is chosen already -- josh - gAgent.setOutfitChosen(TRUE); - } - } - - // release avatar picker keyboard focus - gFocusMgr.setKeyboardFocus( NULL ); - - return true; - } + { + LLSD::UUID folder_uuid; + + if (folder_uuid.isNull() && query_map.has("folder_name")) + { + std::string outfit_folder_name = query_map["folder_name"]; + folder_uuid = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + } + if (folder_uuid.isNull() && query_map.has("folder_id")) + { + folder_uuid = query_map["folder_id"].asUUID(); + } + + if (folder_uuid.notNull()) + { + LLPointer category = new LLInventoryCategory(folder_uuid, + LLUUID::null, + LLFolderType::FT_CLOTHING, + "Quick Appearance"); + if ( gInventory.getCategory( folder_uuid ) != NULL ) + { + // Assume this is coming from the predefined avatars web floater + LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance"); + LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); + + // *TODOw: This may not be necessary if initial outfit is chosen already -- josh + gAgent.setOutfitChosen(TRUE); + } + } + + // release avatar picker keyboard focus + gFocusMgr.setKeyboardFocus( NULL ); + + return true; + } }; LLWearFolderHandler gWearFolderHandler; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6cc2deea80..be000473ba 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -109,7 +109,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llperfstats.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -149,7 +149,7 @@ #include #if LL_WINDOWS -# include // For _SH_DENYWR in processMarkerFiles +# include // For _SH_DENYWR in processMarkerFiles #else # include // For processMarkerFiles #endif @@ -317,16 +317,16 @@ const char* gPlatform = LL_PLATFORM_KEY; LLSD gDebugInfo; -U32 gFrameCount = 0; +U32 gFrameCount = 0; U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground LLPumpIO* gServicePump = NULL; U64MicrosecondsImplicit gFrameTime = 0; F32SecondsImplicit gFrameTimeSeconds = 0.f; F32SecondsImplicit gFrameIntervalSeconds = 0.f; -F32 gFPSClamped = 10.f; // Pretend we start at target rate. -F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets -U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds +F32 gFPSClamped = 10.f; // Pretend we start at target rate. +F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets +U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds LLTimer gRenderStartTime; LLFrameTimer gForegroundTime; @@ -339,24 +339,24 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME; S32 gPendingMetricsUploads = 0; -BOOL gDisconnected = FALSE; +BOOL gDisconnected = FALSE; // used to restore texture state after a mode switch -LLFrameTimer gRestoreGLTimer; -BOOL gRestoreGL = FALSE; -bool gUseWireframe = FALSE; +LLFrameTimer gRestoreGLTimer; +BOOL gRestoreGL = FALSE; +bool gUseWireframe = FALSE; LLMemoryInfo gSysMemory; U64Bytes gMemoryAllocated(0); // updated in display_stats() in llviewerdisplay.cpp std::string gLastVersionChannel; -LLVector3 gWindVec(3.0, 3.0, 0.0); -LLVector3 gRelativeWindVec(0.0, 0.0, 0.0); +LLVector3 gWindVec(3.0, 3.0, 0.0); +LLVector3 gRelativeWindVec(0.0, 0.0, 0.0); -U32 gPacketsIn = 0; +U32 gPacketsIn = 0; -BOOL gPrintMessagesThisFrame = FALSE; +BOOL gPrintMessagesThisFrame = FALSE; BOOL gRandomizeFramerate = FALSE; BOOL gPeriodicSlowFrame = FALSE; @@ -394,53 +394,53 @@ void processComposeSwitch(const std::string&, const std::string&, static std::set default_trans_args; void init_default_trans_args() { - default_trans_args.insert("SECOND_LIFE"); // World - default_trans_args.insert("APP_NAME"); - default_trans_args.insert("CAPITALIZED_APP_NAME"); - default_trans_args.insert("SECOND_LIFE_GRID"); - default_trans_args.insert("SUPPORT_SITE"); - // This URL shows up in a surprising number of places in various skin - // files. We really only want to have to maintain a single copy of it. - default_trans_args.insert("create_account_url"); + default_trans_args.insert("SECOND_LIFE"); // World + default_trans_args.insert("APP_NAME"); + default_trans_args.insert("CAPITALIZED_APP_NAME"); + default_trans_args.insert("SECOND_LIFE_GRID"); + default_trans_args.insert("SUPPORT_SITE"); + // This URL shows up in a surprising number of places in various skin + // files. We really only want to have to maintain a single copy of it. + default_trans_args.insert("create_account_url"); } struct SettingsFile : public LLInitParam::Block { - Mandatory name; - Optional file_name; - Optional required, - persistent; - Optional file_name_setting; - - SettingsFile() - : name("name"), - file_name("file_name"), - required("required", false), - persistent("persistent", true), - file_name_setting("file_name_setting") - {} + Mandatory name; + Optional file_name; + Optional required, + persistent; + Optional file_name_setting; + + SettingsFile() + : name("name"), + file_name("file_name"), + required("required", false), + persistent("persistent", true), + file_name_setting("file_name_setting") + {} }; struct SettingsGroup : public LLInitParam::Block { - Mandatory name; - Mandatory path_index; - Multiple files; - - SettingsGroup() - : name("name"), - path_index("path_index"), - files("file") - {} + Mandatory name; + Mandatory path_index; + Multiple files; + + SettingsGroup() + : name("name"), + path_index("path_index"), + files("file") + {} }; struct SettingsFiles : public LLInitParam::Block { - Multiple groups; + Multiple groups; - SettingsFiles() - : groups("group") - {} + SettingsFiles() + : groups("group") + {} }; static std::string gWindowTitle; @@ -455,122 +455,122 @@ static bool app_metrics_qa_mode = false; void idle_afk_check() { - // check idle timers - F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); - F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); - if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) - { - LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; - gAgent.setAFK(); - } + // check idle timers + F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); + F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); + if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) + { + LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; + gAgent.setAFK(); + } } // A callback set in LLAppViewer::init() static void ui_audio_callback(const LLUUID& uuid) { - if (gAudiop) - { - SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - gAudiop->triggerSound(soundData); - } + if (gAudiop) + { + SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + gAudiop->triggerSound(soundData); + } } // A callback set in LLAppViewer::init() static void deferred_ui_audio_callback(const LLUUID& uuid) { - if (gAudiop) - { - SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - LLDeferredSounds::instance().deferSound(soundData); - } + if (gAudiop) + { + SoundData soundData(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + LLDeferredSounds::instance().deferSound(soundData); + } } -bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) +bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) { - if(!match || !base || base->getPlainText()) - return false; - - LLUUID match_id = match->getID(); - - LLIconCtrl* icon; - - if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor - || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group - { - LLGroupIconCtrl::Params icon_params; - icon_params.group_id = match_id; - icon_params.rect = LLRect(0, 16, 16, 0); - icon_params.visible = true; - icon = LLUICtrlFactory::instance().create(icon_params); - } - else - { - LLAvatarIconCtrl::Params icon_params; - icon_params.avatar_id = match_id; - icon_params.rect = LLRect(0, 16, 16, 0); - icon_params.visible = true; - icon = LLUICtrlFactory::instance().create(icon_params); - } - - LLInlineViewSegment::Params params; - params.force_newline = false; - params.view = icon; - params.left_pad = 4; - params.right_pad = 4; - params.top_pad = -2; - params.bottom_pad = 2; - - base->appendWidget(params," ",false); - - return true; + if(!match || !base || base->getPlainText()) + return false; + + LLUUID match_id = match->getID(); + + LLIconCtrl* icon; + + if( match->getMenuName() == "menu_url_group.xml" // See LLUrlEntryGroup constructor + || gAgent.isInGroup(match_id, TRUE)) //This check seems unfiting, urls are either /agent or /group + { + LLGroupIconCtrl::Params icon_params; + icon_params.group_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().create(icon_params); + } + else + { + LLAvatarIconCtrl::Params icon_params; + icon_params.avatar_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().create(icon_params); + } + + LLInlineViewSegment::Params params; + params.force_newline = false; + params.view = icon; + params.left_pad = 4; + params.right_pad = 4; + params.top_pad = -2; + params.bottom_pad = 2; + + base->appendWidget(params," ",false); + + return true; } // Use these strictly for things that are constructed at startup, // or for things that are performance critical. JC static void settings_to_globals() { - LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); - BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); - BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); + LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); + BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); + BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); - MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); - MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); + MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); + MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); - LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); + LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); #if LL_DARWIN LLRender::sGLCoreProfile = true; #else LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile"); #endif - LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); - LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); - LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); - LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); - LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; - LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); - LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); - LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); - LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); - LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); - LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); - // clamp auto-open time to some minimum usable value - LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay")); - LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive"); - LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); - LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); - - gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); - gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); - gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); - - gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); - gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); + LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); + LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); + LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); + LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); + LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; + LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); + LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); + LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); + LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); + // clamp auto-open time to some minimum usable value + LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay")); + LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive"); + LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); + LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); + + gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns")); + gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns")); + gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); + + gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); + gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale")); - + #if LL_DARWIN LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL"); - gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); + gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); #endif } @@ -588,41 +588,41 @@ static void settings_modify() class LLFastTimerLogThread : public LLThread { public: - std::string mFile; - - LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") - { - std::string file_name = test_name + std::string(".slp"); - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); - } - - void run() - { - llofstream os(mFile.c_str()); - - while (!LLAppViewer::instance()->isQuitting()) - { - LLTrace::BlockTimer::writeLog(os); - os.flush(); - ms_sleep(32); - } - - os.close(); - } + std::string mFile; + + LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") + { + std::string file_name = test_name + std::string(".slp"); + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); + } + + void run() + { + llofstream os(mFile.c_str()); + + while (!LLAppViewer::instance()->isQuitting()) + { + LLTrace::BlockTimer::writeLog(os); + os.flush(); + ms_sleep(32); + } + + os.close(); + } }; //virtual bool LLAppViewer::initSLURLHandler() { - // does nothing unless subclassed - return false; + // does nothing unless subclassed + return false; } //virtual bool LLAppViewer::sendURLToOtherInstance(const std::string& url) { - // does nothing unless subclassed - return false; + // does nothing unless subclassed + return false; } //---------------------------------------------------------------------------- @@ -638,402 +638,402 @@ LLPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL; std::string getRuntime() { - return llformat("%.4f", (F32)LLTimer::getElapsedSeconds().value()); + return llformat("%.4f", (F32)LLTimer::getElapsedSeconds().value()); } LLAppViewer::LLAppViewer() -: mMarkerFile(), - mLogoutMarkerFile(), - mReportedCrash(false), - mNumSessions(0), +: mMarkerFile(), + mLogoutMarkerFile(), + mReportedCrash(false), + mNumSessions(0), mGeneralThreadPool(nullptr), - mPurgeCache(false), - mPurgeCacheOnExit(false), - mPurgeUserDataOnExit(false), - mSecondInstance(false), - mUpdaterNotFound(false), - mSavedFinalSnapshot(false), - mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. - mQuitRequested(false), - mLogoutRequestSent(false), - mLastAgentControlFlags(0), - mLastAgentForceUpdate(0), - mMainloopTimeout(NULL), - mAgentRegionLastAlive(false), - mRandomizeFramerate(LLCachedControl(gSavedSettings,"Randomize Framerate", FALSE)), - mPeriodicSlowFrame(LLCachedControl(gSavedSettings,"Periodic Slow Frame", FALSE)), - mFastTimerLogThread(NULL), - mSettingsLocationList(NULL), - mIsFirstRun(false) + mPurgeCache(false), + mPurgeCacheOnExit(false), + mPurgeUserDataOnExit(false), + mSecondInstance(false), + mUpdaterNotFound(false), + mSavedFinalSnapshot(false), + mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. + mQuitRequested(false), + mLogoutRequestSent(false), + mLastAgentControlFlags(0), + mLastAgentForceUpdate(0), + mMainloopTimeout(NULL), + mAgentRegionLastAlive(false), + mRandomizeFramerate(LLCachedControl(gSavedSettings,"Randomize Framerate", FALSE)), + mPeriodicSlowFrame(LLCachedControl(gSavedSettings,"Periodic Slow Frame", FALSE)), + mFastTimerLogThread(NULL), + mSettingsLocationList(NULL), + mIsFirstRun(false) { - if(NULL != sInstance) - { - LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; - } + if(NULL != sInstance) + { + LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; + } mDumpPath =""; - // Need to do this initialization before we do anything else, since anything - // that touches files should really go through the lldir API - gDirUtilp->initAppDirs("SecondLife"); - // - // IMPORTANT! Do NOT put anything that will write - // into the log files during normal startup until AFTER - // we run the "program crashed last time" error handler below. - // - sInstance = this; - - gLoggedInTime.stop(); - - processMarkerFiles(); - // - // OK to write stuff to logs now, we've now crash reported if necessary - // - - LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple()); - - // Under some circumstances we want to read the static_debug_info.log file - // from the previous viewer run between this constructor call and the - // init() call, which will overwrite the static_debug_info.log file for - // THIS run. So setDebugFileNames() early. + // Need to do this initialization before we do anything else, since anything + // that touches files should really go through the lldir API + gDirUtilp->initAppDirs("SecondLife"); + // + // IMPORTANT! Do NOT put anything that will write + // into the log files during normal startup until AFTER + // we run the "program crashed last time" error handler below. + // + sInstance = this; + + gLoggedInTime.stop(); + + processMarkerFiles(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // + + LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple()); + + // Under some circumstances we want to read the static_debug_info.log file + // from the previous viewer run between this constructor call and the + // init() call, which will overwrite the static_debug_info.log file for + // THIS run. So setDebugFileNames() early. # ifdef LL_BUGSPLAT - // MAINT-8917: don't create a dump directory just for the - // static_debug_info.log file - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + // MAINT-8917: don't create a dump directory just for the + // static_debug_info.log file + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); # else // ! LL_BUGSPLAT - // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); # endif // ! LL_BUGSPLAT - mDumpPath = logdir; + mDumpPath = logdir; - setDebugFileNames(logdir); + setDebugFileNames(logdir); } LLAppViewer::~LLAppViewer() { - delete mSettingsLocationList; + delete mSettingsLocationList; - destroyMainloopTimeout(); + destroyMainloopTimeout(); - // If we got to this destructor somehow, the app didn't hang. - removeMarkerFiles(); + // If we got to this destructor somehow, the app didn't hang. + removeMarkerFiles(); } class LLUITranslationBridge : public LLTranslationBridge { public: - virtual std::string getString(const std::string &xml_desc) - { - return LLTrans::getString(xml_desc); - } + virtual std::string getString(const std::string &xml_desc) + { + return LLTrans::getString(xml_desc); + } }; bool LLAppViewer::init() { - setupErrorHandling(mSecondInstance); + setupErrorHandling(mSecondInstance); - // - // Start of the application - // + // + // Start of the application + // // initialize the LLSettingsType translation bridge. LLTranslationBridge::ptr_t trans = std::make_shared(); LLSettingsType::initParamSingleton(trans); - // initialize SSE options - LLVector4a::initClass(); + // initialize SSE options + LLVector4a::initClass(); - //initialize particle index pool - LLVOPartGroup::initClass(); + //initialize particle index pool + LLVOPartGroup::initClass(); - // set skin search path to default, will be overridden later - // this allows simple skinned file lookups to work - gDirUtilp->setSkinFolder("default", "en"); + // set skin search path to default, will be overridden later + // this allows simple skinned file lookups to work + gDirUtilp->setSkinFolder("default", "en"); -// initLoggingAndGetLastDuration(); +// initLoggingAndGetLastDuration(); - // - // OK to write stuff to logs now, we've now crash reported if necessary - // - init_default_trans_args(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // + init_default_trans_args(); // inits from settings.xml and from strings.xml - if (!initConfiguration()) - return false; + if (!initConfiguration()) + return false; - LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; - //set the max heap size. - initMaxHeapSize() ; - LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); + //set the max heap size. + initMaxHeapSize() ; + LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); - // Although initLoggingAndGetLastDuration() is the right place to mess with - // setFatalFunction(), we can't query gSavedSettings until after - // initConfiguration(). - S32 rc(gSavedSettings.getS32("QAModeTermCode")); - if (rc >= 0) - { - // QAModeTermCode set, terminate with that rc on LL_ERRS. Use - // _exit() rather than exit() because normal cleanup depends too - // much on successful startup! - LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); - } + // Although initLoggingAndGetLastDuration() is the right place to mess with + // setFatalFunction(), we can't query gSavedSettings until after + // initConfiguration(). + S32 rc(gSavedSettings.getS32("QAModeTermCode")); + if (rc >= 0) + { + // QAModeTermCode set, terminate with that rc on LL_ERRS. Use + // _exit() rather than exit() because normal cleanup depends too + // much on successful startup! + LLError::setFatalFunction([rc](const std::string&){ _exit(rc); }); + } mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); - // Initialize the non-LLCurl libcurl library. Should be called - // before consumers (LLTextureFetch). - mAppCoreHttp.init(); + // Initialize the non-LLCurl libcurl library. Should be called + // before consumers (LLTextureFetch). + mAppCoreHttp.init(); - LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; LLMachineID::init(); - { - if (gSavedSettings.getBOOL("QAModeMetrics")) - { - app_metrics_qa_mode = true; - app_metrics_interval = METRICS_INTERVAL_QA; - } - LLViewerAssetStatsFF::init(); - } - - initThreads(); - LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; - - // Initialize settings early so that the defaults for ignorable dialogs are - // picked up and then correctly re-saved after launching the updater (STORM-1268). - LLUI::settings_map_t settings_map; - settings_map["config"] = &gSavedSettings; - settings_map["ignores"] = &gWarningSettings; - settings_map["floater"] = &gSavedSettings; // *TODO: New settings file - settings_map["account"] = &gSavedPerAccountSettings; - - LLUI::initParamSingleton(settings_map, - LLUIImageList::getInstance(), - ui_audio_callback, - deferred_ui_audio_callback); - LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; - - // NOW LLUI::getLanguage() should work. gDirUtilp must know the language - // for this session ASAP so all the file-loading commands that follow, - // that use findSkinnedFilenames(), will include the localized files. - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); - - // Setup LLTrans after LLUI::initClass has been called. - initStrings(); + { + if (gSavedSettings.getBOOL("QAModeMetrics")) + { + app_metrics_qa_mode = true; + app_metrics_interval = METRICS_INTERVAL_QA; + } + LLViewerAssetStatsFF::init(); + } + + initThreads(); + LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; + + // Initialize settings early so that the defaults for ignorable dialogs are + // picked up and then correctly re-saved after launching the updater (STORM-1268). + LLUI::settings_map_t settings_map; + settings_map["config"] = &gSavedSettings; + settings_map["ignores"] = &gWarningSettings; + settings_map["floater"] = &gSavedSettings; // *TODO: New settings file + settings_map["account"] = &gSavedPerAccountSettings; + + LLUI::initParamSingleton(settings_map, + LLUIImageList::getInstance(), + ui_audio_callback, + deferred_ui_audio_callback); + LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; + + // NOW LLUI::getLanguage() should work. gDirUtilp must know the language + // for this session ASAP so all the file-loading commands that follow, + // that use findSkinnedFilenames(), will include the localized files. + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); + + // Setup LLTrans after LLUI::initClass has been called. + initStrings(); // initialize LLWearableType translation bridge. // Will immediately use LLTranslationBridge to init LLWearableDictionary LLWearableType::initParamSingleton(trans); - // Setup notifications after LLUI::initClass() has been called. - LLNotifications::instance(); - LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; + // Setup notifications after LLUI::initClass() has been called. + LLNotifications::instance(); + LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// - // *FIX: The following code isn't grouped into functions yet. + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + // *FIX: The following code isn't grouped into functions yet. - // - // Various introspection concerning the libs we're using - particularly - // the libs involved in getting to a full login screen. - // - LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; - LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; + // + // Various introspection concerning the libs we're using - particularly + // the libs involved in getting to a full login screen. + // + LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; + LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; - ///////////////////////////////////////////////// - // OS-specific login dialogs - ///////////////////////////////////////////////// + ///////////////////////////////////////////////// + // OS-specific login dialogs + ///////////////////////////////////////////////// - //test_cached_control(); + //test_cached_control(); - // track number of times that app has run - mNumSessions = gSavedSettings.getS32("NumSessions"); - mNumSessions++; - gSavedSettings.setS32("NumSessions", mNumSessions); + // track number of times that app has run + mNumSessions = gSavedSettings.getS32("NumSessions"); + mNumSessions++; + gSavedSettings.setS32("NumSessions", mNumSessions); - // LLKeyboard relies on LLUI to know what some accelerator keys are called. - LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); + // LLKeyboard relies on LLUI to know what some accelerator keys are called. + LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString ); - // Provide the text fields with callbacks for opening Urls - LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); - LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); - LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); - LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); + // Provide the text fields with callbacks for opening Urls + LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); + LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); + LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); + LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); - // Let code in llui access the viewer help floater - LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); + // Let code in llui access the viewer help floater + LLUI::getInstance()->mHelpImpl = LLViewerHelp::getInstance(); - LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; + LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; - // Load translations for tooltips - LLFloater::initClass(); - LLUrlFloaterDispatchHandler::registerInDispatcher(); + // Load translations for tooltips + LLFloater::initClass(); + LLUrlFloaterDispatchHandler::registerInDispatcher(); - ///////////////////////////////////////////////// + ///////////////////////////////////////////////// - LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated + LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated - LLViewerFloaterReg::registerFloaters(); + LLViewerFloaterReg::registerFloaters(); - ///////////////////////////////////////////////// - // - // Load settings files - // - // - LLGroupMgr::parseRoleActions("role_actions.xml"); + ///////////////////////////////////////////////// + // + // Load settings files + // + // + LLGroupMgr::parseRoleActions("role_actions.xml"); - LLAgent::parseTeleportMessages("teleport_strings.xml"); + LLAgent::parseTeleportMessages("teleport_strings.xml"); - // load MIME type -> media impl mappings - std::string mime_types_name; + // load MIME type -> media impl mappings + std::string mime_types_name; #if LL_DARWIN - mime_types_name = "mime_types_mac.xml"; + mime_types_name = "mime_types_mac.xml"; #elif LL_LINUX - mime_types_name = "mime_types_linux.xml"; + mime_types_name = "mime_types_linux.xml"; #else - mime_types_name = "mime_types.xml"; + mime_types_name = "mime_types.xml"; #endif - LLMIMETypes::parseMIMETypes( mime_types_name ); - - // Copy settings to globals. *TODO: Remove or move to appropriage class initializers - settings_to_globals(); - // Setup settings listeners - settings_setup_listeners(); - // Modify settings based on system configuration and compile options - settings_modify(); - - // Find partition serial number (Windows) or hardware serial (Mac) - mSerialNumber = generateSerialNumber(); - - // do any necessary set-up for accepting incoming SLURLs from apps - initSLURLHandler(); - - if(false == initHardwareTest()) - { - // Early out from user choice. - return false; - } - LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; - - // Prepare for out-of-memory situations, during which we will crash on - // purpose and save a dump. + LLMIMETypes::parseMIMETypes( mime_types_name ); + + // Copy settings to globals. *TODO: Remove or move to appropriage class initializers + settings_to_globals(); + // Setup settings listeners + settings_setup_listeners(); + // Modify settings based on system configuration and compile options + settings_modify(); + + // Find partition serial number (Windows) or hardware serial (Mac) + mSerialNumber = generateSerialNumber(); + + // do any necessary set-up for accepting incoming SLURLs from apps + initSLURLHandler(); + + if(false == initHardwareTest()) + { + // Early out from user choice. + return false; + } + LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ; + + // Prepare for out-of-memory situations, during which we will crash on + // purpose and save a dump. #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP - MemSetErrorHandler(first_mem_error_handler); + MemSetErrorHandler(first_mem_error_handler); #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP - // *Note: this is where gViewerStats used to be created. + // *Note: this is where gViewerStats used to be created. - if (!initCache()) - { - LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; - std::ostringstream msg; - msg << LLTrans::getString("MBUnableToAccessFile"); - OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); - return 0; - } - LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; + if (!initCache()) + { + LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; + std::ostringstream msg; + msg << LLTrans::getString("MBUnableToAccessFile"); + OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); + return 0; + } + LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; // Initialize event recorder LLViewerEventRecorder::createInstance(); - // - // Initialize the window - // - gGLActive = TRUE; - initWindow(); - LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; + // + // Initialize the window + // + gGLActive = TRUE; + initWindow(); + LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; // writeSystemInfo can be called after window is initialized (gViewerWindow non-null) writeSystemInfo(); - // initWindow also initializes the Feature List, so now we can initialize this global. - LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); + // initWindow also initializes the Feature List, so now we can initialize this global. + LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); - // call all self-registered classes - LLInitClassList::instance().fireCallbacks(); + // call all self-registered classes + LLInitClassList::instance().fireCallbacks(); - LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts + LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts - gGLManager.getGLInfo(gDebugInfo); - gGLManager.printGLInfoString(); + gGLManager.getGLInfo(gDebugInfo); + gGLManager.printGLInfoString(); - // If we don't have the right GL requirements, exit. - if (!gGLManager.mHasRequirements) - { + // If we don't have the right GL requirements, exit. + if (!gGLManager.mHasRequirements) + { // already handled with a MBVideoDrvErr - return 0; - } - - // Without SSE2 support we will crash almost immediately, warn here. - if (!gSysCPU.hasSSE2()) - { - // can't use an alert here since we're exiting and - // all hell breaks lose. - OSMessageBox( - LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), - LLStringUtil::null, - OSMB_OK); - return 0; - } - - // alert the user if they are using unsupported hardware - if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) - { - bool unsupported = false; - LLSD args; - std::string minSpecs; - - // get cpu data from xml - std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); - S32 minCPU = 0; - minCPUString >> minCPU; - - // get RAM data from XML - std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); - U64Bytes minRAM; - minRAMString >> minRAM; - - if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysCPU.getMHz() < minCPU) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysMemory.getPhysicalMemoryKB() < minRAM) - { - minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); - minSpecs += "\n"; - unsupported = true; - } - - if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) - { - LLNotificationsUtil::add("UnknownGPU"); - } - - if(unsupported) - { - if(!gSavedSettings.controlExists("WarnUnsupportedHardware") - || gSavedSettings.getBOOL("WarnUnsupportedHardware")) - { - args["MINSPECS"] = minSpecs; - LLNotificationsUtil::add("UnsupportedHardware", args ); - } - - } - } + return 0; + } + + // Without SSE2 support we will crash almost immediately, warn here. + if (!gSysCPU.hasSSE2()) + { + // can't use an alert here since we're exiting and + // all hell breaks lose. + OSMessageBox( + LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), + LLStringUtil::null, + OSMB_OK); + return 0; + } + + // alert the user if they are using unsupported hardware + if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) + { + bool unsupported = false; + LLSD args; + std::string minSpecs; + + // get cpu data from xml + std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); + S32 minCPU = 0; + minCPUString >> minCPU; + + // get RAM data from XML + std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); + U64Bytes minRAM; + minRAMString >> minRAM; + + if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysCPU.getMHz() < minCPU) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysMemory.getPhysicalMemoryKB() < minRAM) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); + minSpecs += "\n"; + unsupported = true; + } + + if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) + { + LLNotificationsUtil::add("UnknownGPU"); + } + + if(unsupported) + { + if(!gSavedSettings.controlExists("WarnUnsupportedHardware") + || gSavedSettings.getBOOL("WarnUnsupportedHardware")) + { + args["MINSPECS"] = minSpecs; + LLNotificationsUtil::add("UnsupportedHardware", args ); + } + + } + } #if LL_WINDOWS && ADDRESS_SIZE == 64 if (gGLManager.mIsIntel) @@ -1084,54 +1084,54 @@ bool LLAppViewer::init() // Obsolete? mExpectedGLVersion is always zero #if LL_WINDOWS - if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) - { - std::string url; - if (gGLManager.mIsIntel) - { - url = LLTrans::getString("IntelDriverPage"); - } - else if (gGLManager.mIsNVIDIA) - { - url = LLTrans::getString("NvidiaDriverPage"); - } - else if (gGLManager.mIsAMD) - { - url = LLTrans::getString("AMDDriverPage"); - } - - if (!url.empty()) - { - LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); - } - } + if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) + { + std::string url; + if (gGLManager.mIsIntel) + { + url = LLTrans::getString("IntelDriverPage"); + } + else if (gGLManager.mIsNVIDIA) + { + url = LLTrans::getString("NvidiaDriverPage"); + } + else if (gGLManager.mIsAMD) + { + url = LLTrans::getString("AMDDriverPage"); + } + + if (!url.empty()) + { + LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); + } + } #endif - // save the graphics card - gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); + // save the graphics card + gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); - // Save the current version to the prefs file - gSavedSettings.setString("LastRunVersion", - LLVersionInfo::instance().getChannelAndVersion()); + // Save the current version to the prefs file + gSavedSettings.setString("LastRunVersion", + LLVersionInfo::instance().getChannelAndVersion()); - gSimLastTime = gRenderStartTime.getElapsedTimeF32(); - gSimFrames = (F32)gFrameCount; + gSimLastTime = gRenderStartTime.getElapsedTimeF32(); + gSimFrames = (F32)gFrameCount; if (gSavedSettings.getBOOL("JoystickEnabled")) { LLViewerJoystick::getInstance()->init(false); } - try { - initializeSecHandler(); - } - catch (LLProtectedDataException&) - { - LLNotificationsUtil::add("CorruptedProtectedDataStore"); - } + try { + initializeSecHandler(); + } + catch (LLProtectedDataException&) + { + LLNotificationsUtil::add("CorruptedProtectedDataStore"); + } - gGLActive = FALSE; + gGLActive = FALSE; #if LL_RELEASE_FOR_DOWNLOAD // Skip updater if this is a non-interactive instance @@ -1230,25 +1230,25 @@ bool LLAppViewer::init() << LL_ENDL; } - LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; + LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; - //EXT-7013 - On windows for some locale (Japanese) standard - //datetime formatting functions didn't support some parameters such as "weekday". - //Names for days and months localized in xml are also useful for Polish locale(STORM-107). - std::string language = gSavedSettings.getString("Language"); - if(language == "ja" || language == "pl") - { - LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames")); - LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames")); - LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames")); - LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames")); - LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat")); - - LLStringOps::sAM = LLTrans::getString("dateTimeAM"); - LLStringOps::sPM = LLTrans::getString("dateTimePM"); - } + //EXT-7013 - On windows for some locale (Japanese) standard + //datetime formatting functions didn't support some parameters such as "weekday". + //Names for days and months localized in xml are also useful for Polish locale(STORM-107). + std::string language = gSavedSettings.getString("Language"); + if(language == "ja" || language == "pl") + { + LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames")); + LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames")); + LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames")); + LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames")); + LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat")); + + LLStringOps::sAM = LLTrans::getString("dateTimeAM"); + LLStringOps::sPM = LLTrans::getString("dateTimePM"); + } - LLAgentLanguage::init(); + LLAgentLanguage::init(); /// Tell the Coprocedure manager how to discover and store the pool sizes // what I wanted @@ -1256,27 +1256,27 @@ bool LLAppViewer::init() boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1), boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS)); - // TODO: consider moving proxy initialization here or LLCopocedureManager after proxy initialization, may be implement - // some other protection to make sure we don't use network before initializng proxy + // TODO: consider moving proxy initialization here or LLCopocedureManager after proxy initialization, may be implement + // some other protection to make sure we don't use network before initializng proxy - /*----------------------------------------------------------------------*/ - // nat 2016-06-29 moved the following here from the former mainLoop(). - mMainloopTimeout = new LLWatchdogTimeout(); + /*----------------------------------------------------------------------*/ + // nat 2016-06-29 moved the following here from the former mainLoop(). + mMainloopTimeout = new LLWatchdogTimeout(); - // Create IO Pump to use for HTTP Requests. - gServicePump = new LLPumpIO(gAPRPoolp); + // Create IO Pump to use for HTTP Requests. + gServicePump = new LLPumpIO(gAPRPoolp); - // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. - LLVoiceChannel::initClass(); - LLVoiceClient::initParamSingleton(gServicePump); - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); + LLVoiceChannel::initClass(); + LLVoiceClient::initParamSingleton(gServicePump); + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); - joystick = LLViewerJoystick::getInstance(); - joystick->setNeedsReset(true); - /*----------------------------------------------------------------------*/ - // Load User's bindings - loadKeyBindings(); + joystick = LLViewerJoystick::getInstance(); + joystick->setNeedsReset(true); + /*----------------------------------------------------------------------*/ + // Load User's bindings + loadKeyBindings(); //LLSimpleton creations LLEnvironment::createInstance(); @@ -1291,7 +1291,7 @@ bool LLAppViewer::init() } #endif - return true; + return true; } void processComposeSwitch(const std::string& option, @@ -1317,18 +1317,18 @@ void processComposeSwitch(const std::string& option, void LLAppViewer::initMaxHeapSize() { - //set the max heap size. - //here is some info regarding to the max heap size: - //------------------------------------------------------------------------------------------ - // OS | setting | SL address bits | max manageable memory space | max heap size - // Win 32 | default | 32-bit | 2GB | < 1.7GB - // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB - //Linux 32 | default | 32-bit | 3GB | < 2.7GB - //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB - //64-bit OS |default | 32-bit | 4GB | < 3.7GB - //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) - //------------------------------------------------------------------------------------------ - //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. + //set the max heap size. + //here is some info regarding to the max heap size: + //------------------------------------------------------------------------------------------ + // OS | setting | SL address bits | max manageable memory space | max heap size + // Win 32 | default | 32-bit | 2GB | < 1.7GB + // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB + //Linux 32 | default | 32-bit | 3GB | < 2.7GB + //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) + //------------------------------------------------------------------------------------------ + //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. #ifndef LL_X86_64 F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; @@ -1345,42 +1345,42 @@ LLTrace::BlockTimerStatHandle FTM_FRAME("Frame"); bool LLAppViewer::frame() { - bool ret = false; - - if (gSimulateMemLeak) - { - try - { - ret = doFrame(); - } - catch (const LLContinueError&) - { - LOG_UNHANDLED_EXCEPTION(""); - } - catch (std::bad_alloc&) - { - LLMemory::logMemoryInfo(TRUE); - LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance("mem_leaking"); - if (mem_leak_instance) - { - mem_leak_instance->stop(); - } - LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL; - } - } - else - { - try - { - ret = doFrame(); - } - catch (const LLContinueError&) - { - LOG_UNHANDLED_EXCEPTION(""); - } - } - - return ret; + bool ret = false; + + if (gSimulateMemLeak) + { + try + { + ret = doFrame(); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); + } + catch (std::bad_alloc&) + { + LLMemory::logMemoryInfo(TRUE); + LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance("mem_leaking"); + if (mem_leak_instance) + { + mem_leak_instance->stop(); + } + LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL; + } + } + else + { + try + { + ret = doFrame(); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); + } + } + + return ret; } bool LLAppViewer::doFrame() @@ -1473,63 +1473,63 @@ bool LLAppViewer::doFrame() } } - if (!LLApp::isExiting()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) - pingMainloopTimeout("Main:JoystickKeyboard"); - - // Scan keyboard for movement keys. Command keys and typing - // are handled by windows callbacks. Don't do this until we're - // done initializing. JC - if (gViewerWindow - && (gHeadlessClient || gViewerWindow->getWindow()->getVisible()) - && gViewerWindow->getActive() - && !gViewerWindow->getWindow()->getMinimized() - && LLStartUp::getStartupState() == STATE_STARTED - && (gHeadlessClient || !gViewerWindow->getShowProgress()) - && !gFocusMgr.focusLocked()) - { + if (!LLApp::isExiting()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) + pingMainloopTimeout("Main:JoystickKeyboard"); + + // Scan keyboard for movement keys. Command keys and typing + // are handled by windows callbacks. Don't do this until we're + // done initializing. JC + if (gViewerWindow + && (gHeadlessClient || gViewerWindow->getWindow()->getVisible()) + && gViewerWindow->getActive() + && !gViewerWindow->getWindow()->getMinimized() + && LLStartUp::getStartupState() == STATE_STARTED + && (gHeadlessClient || !gViewerWindow->getShowProgress()) + && !gFocusMgr.focusLocked()) + { LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); - joystick->scanJoystick(); - gKeyboard->scanKeyboard(); + joystick->scanJoystick(); + gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); - } + } - // Update state based on messages, user input, object idle. - { - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) - pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! - } + // Update state based on messages, user input, object idle. + { + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! + } - { + { LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); - idle(); - } + idle(); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) - resumeMainloopTimeout(); - } - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } + } - if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) - { - pauseMainloopTimeout(); - saveFinalSnapshot(); + if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) + { + pauseMainloopTimeout(); + saveFinalSnapshot(); if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->terminate(); } - disconnectViewer(); - resumeMainloopTimeout(); - } + disconnectViewer(); + resumeMainloopTimeout(); + } - // Render scene. - // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 + // Render scene. + // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Display"); @@ -1553,159 +1553,159 @@ bool LLAppViewer::doFrame() LLViewerStatsRecorder::instance().idle(); } } - } + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) - pingMainloopTimeout("Main:Sleep"); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pingMainloopTimeout("Main:Sleep"); - pauseMainloopTimeout(); - } + pauseMainloopTimeout(); + } - // Sleep and run background threads - { - //LL_RECORD_BLOCK_TIME(SLEEP2); - LL_PROFILE_ZONE_WARN( "Sleep2" ) + // Sleep and run background threads + { + //LL_RECORD_BLOCK_TIME(SLEEP2); + LL_PROFILE_ZONE_WARN( "Sleep2" ) - // yield some time to the os based on command line option - static LLCachedControl yield_time(gSavedSettings, "YieldTime", -1); - if(yield_time >= 0) - { + // yield some time to the os based on command line option + static LLCachedControl yield_time(gSavedSettings, "YieldTime", -1); + if(yield_time >= 0) + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Yield"); - LL_PROFILE_ZONE_NUM( yield_time ) - ms_sleep(yield_time); - } - - if (gNonInteractive) - { - S32 non_interactive_ms_sleep_time = 100; - LLAppViewer::getTextureCache()->pause(); - ms_sleep(non_interactive_ms_sleep_time); - } - - // yield cooperatively when not running as foreground window - // and when not quiting (causes trouble at mac's cleanup stage) - if (!LLApp::isExiting() - && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) - || !gFocusMgr.getAppHasFocus())) - { - // Sleep if we're not rendering, or the window is minimized. - static LLCachedControl s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); - S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); - // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads - // of equal priority on Windows - if (milliseconds_to_sleep > 0) - { + LL_PROFILE_ZONE_NUM( yield_time ) + ms_sleep(yield_time); + } + + if (gNonInteractive) + { + S32 non_interactive_ms_sleep_time = 100; + LLAppViewer::getTextureCache()->pause(); + ms_sleep(non_interactive_ms_sleep_time); + } + + // yield cooperatively when not running as foreground window + // and when not quiting (causes trouble at mac's cleanup stage) + if (!LLApp::isExiting() + && ((gViewerWindow && !gViewerWindow->getWindow()->getVisible()) + || !gFocusMgr.getAppHasFocus())) + { + // Sleep if we're not rendering, or the window is minimized. + static LLCachedControl s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); + // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads + // of equal priority on Windows + if (milliseconds_to_sleep > 0) + { LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); - // also pause worker threads during this wait period - LLAppViewer::getTextureCache()->pause(); - } - } - - if (mRandomizeFramerate) - { - ms_sleep(rand() % 200); - } - - if (mPeriodicSlowFrame - && (gFrameCount % 10 == 0)) - { - LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; - ms_sleep(500); - } - - S32 total_work_pending = 0; - S32 total_io_pending = 0; - { - S32 work_pending = 0; - S32 io_pending = 0; - F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f); - - work_pending += updateTextureThreads(max_time); - - { + // also pause worker threads during this wait period + LLAppViewer::getTextureCache()->pause(); + } + } + + if (mRandomizeFramerate) + { + ms_sleep(rand() % 200); + } + + if (mPeriodicSlowFrame + && (gFrameCount % 10 == 0)) + { + LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; + ms_sleep(500); + } + + S32 total_work_pending = 0; + S32 total_io_pending = 0; + { + S32 work_pending = 0; + S32 io_pending = 0; + F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f); + + work_pending += updateTextureThreads(max_time); + + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("LFS Thread"); - io_pending += LLLFSThread::updateClass(1); - } - - if (io_pending > 1000) - { - ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up - } - - total_work_pending += work_pending ; - total_io_pending += io_pending ; - - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) - gMeshRepo.update() ; - } - - if(!total_work_pending) //pause texture fetching threads if nothing to process. - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) - LLAppViewer::getTextureCache()->pause(); - LLAppViewer::getTextureFetch()->pause(); - } - if(!total_io_pending) //pause file threads if nothing to process. - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) - LLLFSThread::sLocal->pause(); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) - resumeMainloopTimeout(); - } - pingMainloopTimeout("Main:End"); - } - } - - if (LLApp::isExiting()) - { - // Save snapshot for next time, if we made it through initialization - if (STATE_STARTED == LLStartUp::getStartupState()) - { - saveFinalSnapshot(); - } - - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->terminate(); - } - - delete gServicePump; - gServicePump = NULL; - - destroyMainloopTimeout(); - - LL_INFOS() << "Exiting main_loop" << LL_ENDL; - } + io_pending += LLLFSThread::updateClass(1); + } + + if (io_pending > 1000) + { + ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up + } + + total_work_pending += work_pending ; + total_io_pending += io_pending ; + + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) + gMeshRepo.update() ; + } + + if(!total_work_pending) //pause texture fetching threads if nothing to process. + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) + LLAppViewer::getTextureCache()->pause(); + LLAppViewer::getTextureFetch()->pause(); + } + if(!total_io_pending) //pause file threads if nothing to process. + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) + LLLFSThread::sLocal->pause(); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } + pingMainloopTimeout("Main:End"); + } + } + + if (LLApp::isExiting()) + { + // Save snapshot for next time, if we made it through initialization + if (STATE_STARTED == LLStartUp::getStartupState()) + { + saveFinalSnapshot(); + } + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->terminate(); + } + + delete gServicePump; + gServicePump = NULL; + + destroyMainloopTimeout(); + + LL_INFOS() << "Exiting main_loop" << LL_ENDL; + } }LLPerfStats::StatsRecorder::endFrame(); LL_PROFILER_FRAME_END - return ! LLApp::isRunning(); + return ! LLApp::isRunning(); } S32 LLAppViewer::updateTextureThreads(F32 max_time) { - S32 work_pending = 0; - { + S32 work_pending = 0; + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Texture Cache"); - work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread - } - { + work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + } + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Image Decode"); - work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread - } - { + work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + } + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Image Fetch"); - work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread - } - return work_pending; + work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + } + return work_pending; } void LLAppViewer::flushLFSIO() @@ -1730,200 +1730,200 @@ bool LLAppViewer::cleanup() { LLAtmosphere::cleanupClass(); - //ditch LLVOAvatarSelf instance - gAgentAvatarp = NULL; + //ditch LLVOAvatarSelf instance + gAgentAvatarp = NULL; LLNotifications::instance().clear(); - // workaround for DEV-35406 crash on shutdown - LLEventPumps::instance().reset(true); + // workaround for DEV-35406 crash on shutdown + LLEventPumps::instance().reset(true); - //dump scene loading monitor results - if (LLSceneMonitor::instanceExists()) - { - if (!isSecondInstance()) - { + //dump scene loading monitor results + if (LLSceneMonitor::instanceExists()) + { + if (!isSecondInstance()) + { std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv"); - LLSceneMonitor::instance().dumpToFile(dump_path); - } - LLSceneMonitor::deleteSingleton(); - } - - // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block - // here, completely redundant with the one that occurs later in this same - // function. Presumably the duplication was due to an automated merge gone - // bad. Not knowing which instance to prefer, we chose to retain the later - // one because it happens just after mFastTimerLogThread is deleted. This - // comment is in case we guessed wrong, so we can move it here instead. + LLSceneMonitor::instance().dumpToFile(dump_path); + } + LLSceneMonitor::deleteSingleton(); + } + + // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block + // here, completely redundant with the one that occurs later in this same + // function. Presumably the duplication was due to an automated merge gone + // bad. Not knowing which instance to prefer, we chose to retain the later + // one because it happens just after mFastTimerLogThread is deleted. This + // comment is in case we guessed wrong, so we can move it here instead. #if LL_LINUX - // remove any old breakpad minidump files from the log directory - if (! isError()) - { - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); - gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); - } + // remove any old breakpad minidump files from the log directory + if (! isError()) + { + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); + } #endif - // Kill off LLLeap objects. We can find them all because LLLeap is derived - // from LLInstanceTracker. - LLLeap::instance_snapshot().deleteAll(); + // Kill off LLLeap objects. We can find them all because LLLeap is derived + // from LLInstanceTracker. + LLLeap::instance_snapshot().deleteAll(); - //flag all elements as needing to be destroyed immediately - // to ensure shutdown order - LLMortician::setZealous(TRUE); + //flag all elements as needing to be destroyed immediately + // to ensure shutdown order + LLMortician::setZealous(TRUE); // Give any remaining SLPlugin instances a chance to exit cleanly. LLPluginProcessParent::shutdown(); - disconnectViewer(); - LLViewerCamera::deleteSingleton(); + disconnectViewer(); + LLViewerCamera::deleteSingleton(); + + LL_INFOS() << "Viewer disconnected" << LL_ENDL; - LL_INFOS() << "Viewer disconnected" << LL_ENDL; - - if (gKeyboard) - { - gKeyboard->resetKeys(); - } + if (gKeyboard) + { + gKeyboard->resetKeys(); + } - display_cleanup(); + display_cleanup(); - release_start_screen(); // just in case + release_start_screen(); // just in case - LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder + LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder - LL_INFOS() << "Cleaning Up" << LL_ENDL; + LL_INFOS() << "Cleaning Up" << LL_ENDL; - // shut down mesh streamer - gMeshRepo.shutdown(); + // shut down mesh streamer + gMeshRepo.shutdown(); - // shut down Havok - LLPhysicsExtensions::quitSystem(); + // shut down Havok + LLPhysicsExtensions::quitSystem(); - // Must clean up texture references before viewer window is destroyed. - if(LLHUDManager::instanceExists()) - { - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDObject::cleanupHUDObjects(); - LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; - } + // Must clean up texture references before viewer window is destroyed. + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDObject::cleanupHUDObjects(); + LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; + } - LLKeyframeDataCache::clear(); + LLKeyframeDataCache::clear(); - // End TransferManager before deleting systems it depends on (Audio, AssetStorage) + // End TransferManager before deleting systems it depends on (Audio, AssetStorage) #if 0 // this seems to get us stuck in an infinite loop... - gTransferManager.cleanup(); + gTransferManager.cleanup(); #endif - // Note: this is where gWorldMap used to be deleted. + // Note: this is where gWorldMap used to be deleted. - // Note: this is where gHUDManager used to be deleted. - if(LLHUDManager::instanceExists()) - { - LLHUDManager::getInstance()->shutdownClass(); - } + // Note: this is where gHUDManager used to be deleted. + if(LLHUDManager::instanceExists()) + { + LLHUDManager::getInstance()->shutdownClass(); + } - delete gAssetStorage; - gAssetStorage = NULL; + delete gAssetStorage; + gAssetStorage = NULL; - LLPolyMesh::freeAllMeshes(); + LLPolyMesh::freeAllMeshes(); - LLStartUp::cleanupNameCache(); + LLStartUp::cleanupNameCache(); - // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. - if (LLWorldMap::instanceExists()) - { - LLWorldMap::getInstance()->reset(); // release any images - } + if (LLWorldMap::instanceExists()) + { + LLWorldMap::getInstance()->reset(); // release any images + } - LLCalc::cleanUp(); + LLCalc::cleanUp(); - LL_INFOS() << "Global stuff deleted" << LL_ENDL; + LL_INFOS() << "Global stuff deleted" << LL_ENDL; - if (gAudiop) - { + if (gAudiop) + { LL_INFOS() << "Shutting down audio" << LL_ENDL; // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it. gAudiop->stopInternetStream(); // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); - delete sai; - gAudiop->setStreamingAudioImpl(NULL); + delete sai; + gAudiop->setStreamingAudioImpl(NULL); // shut down the audio subsystem gAudiop->shutdown(); - delete gAudiop; - gAudiop = NULL; - } - - // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. + delete gAudiop; + gAudiop = NULL; + } - // Patch up settings for next time - // Must do this before we delete the viewer window, - // such that we can suck rectangle information out of - // it. - cleanupSavedSettings(); - LL_INFOS() << "Settings patched up" << LL_ENDL; + // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. - // delete some of the files left around in the cache. - removeCacheFiles("*.wav"); - removeCacheFiles("*.tmp"); - removeCacheFiles("*.lso"); - removeCacheFiles("*.out"); - removeCacheFiles("*.dsf"); - removeCacheFiles("*.bodypart"); - removeCacheFiles("*.clothing"); + // Patch up settings for next time + // Must do this before we delete the viewer window, + // such that we can suck rectangle information out of + // it. + cleanupSavedSettings(); + LL_INFOS() << "Settings patched up" << LL_ENDL; - LL_INFOS() << "Cache files removed" << LL_ENDL; + // delete some of the files left around in the cache. + removeCacheFiles("*.wav"); + removeCacheFiles("*.tmp"); + removeCacheFiles("*.lso"); + removeCacheFiles("*.out"); + removeCacheFiles("*.dsf"); + removeCacheFiles("*.bodypart"); + removeCacheFiles("*.clothing"); - LL_INFOS() << "Shutting down Views" << LL_ENDL; + LL_INFOS() << "Cache files removed" << LL_ENDL; - // Destroy the UI - if( gViewerWindow) - gViewerWindow->shutdownViews(); + LL_INFOS() << "Shutting down Views" << LL_ENDL; - LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; + // Destroy the UI + if( gViewerWindow) + gViewerWindow->shutdownViews(); - // Cleanup Inventory after the UI since it will delete any remaining observers - // (Deleted observers should have already removed themselves) - gInventory.cleanupInventory(); + LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; - LLCoros::getInstance()->printActiveCoroutines(); + // Cleanup Inventory after the UI since it will delete any remaining observers + // (Deleted observers should have already removed themselves) + gInventory.cleanupInventory(); - LL_INFOS() << "Cleaning up Selections" << LL_ENDL; + LLCoros::getInstance()->printActiveCoroutines(); - // Clean up selection managers after UI is destroyed, as UI may be observing them. - // Clean up before GL is shut down because we might be holding on to objects with texture references - LLSelectMgr::cleanupGlobals(); + LL_INFOS() << "Cleaning up Selections" << LL_ENDL; - LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; + // Clean up selection managers after UI is destroyed, as UI may be observing them. + // Clean up before GL is shut down because we might be holding on to objects with texture references + LLSelectMgr::cleanupGlobals(); - // Shut down OpenGL - if( gViewerWindow) - { - gViewerWindow->shutdownGL(); + LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; - // Destroy window, and make sure we're not fullscreen - // This may generate window reshape and activation events. - // Therefore must do this before destroying the message system. - delete gViewerWindow; - gViewerWindow = NULL; - LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; - } + // Shut down OpenGL + if( gViewerWindow) + { + gViewerWindow->shutdownGL(); + + // Destroy window, and make sure we're not fullscreen + // This may generate window reshape and activation events. + // Therefore must do this before destroying the message system. + delete gViewerWindow; + gViewerWindow = NULL; + LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; + } LLSplashScreen::show(); LLSplashScreen::update(LLTrans::getString("ShuttingDown")); - LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; + LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; - // viewer UI relies on keyboard so keep it aound until viewer UI isa gone - delete gKeyboard; - gKeyboard = NULL; + // viewer UI relies on keyboard so keep it aound until viewer UI isa gone + delete gKeyboard; + gKeyboard = NULL; if (LLViewerJoystick::instanceExists()) { @@ -1931,280 +1931,280 @@ bool LLAppViewer::cleanup() LLViewerJoystick::getInstance()->terminate(); } - LL_INFOS() << "Cleaning up Objects" << LL_ENDL; + LL_INFOS() << "Cleaning up Objects" << LL_ENDL; - LLViewerObject::cleanupVOClasses(); + LLViewerObject::cleanupVOClasses(); - SUBSYSTEM_CLEANUP(LLAvatarAppearance); + SUBSYSTEM_CLEANUP(LLAvatarAppearance); - SUBSYSTEM_CLEANUP(LLPostProcess); + SUBSYSTEM_CLEANUP(LLPostProcess); - LLTracker::cleanupInstance(); + LLTracker::cleanupInstance(); - // *FIX: This is handled in LLAppViewerWin32::cleanup(). - // I'm keeping the comment to remember its order in cleanup, - // in case of unforseen dependency. - //#if LL_WINDOWS - // gDXHardware.cleanup(); - //#endif // LL_WINDOWS + // *FIX: This is handled in LLAppViewerWin32::cleanup(). + // I'm keeping the comment to remember its order in cleanup, + // in case of unforseen dependency. + //#if LL_WINDOWS + // gDXHardware.cleanup(); + //#endif // LL_WINDOWS - LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); - if (!volume_manager->cleanup()) - { - LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; - } - LLPrimitive::cleanupVolumeManager(); + LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); + if (!volume_manager->cleanup()) + { + LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; + } + LLPrimitive::cleanupVolumeManager(); - LL_INFOS() << "Additional Cleanup..." << LL_ENDL; + LL_INFOS() << "Additional Cleanup..." << LL_ENDL; - LLViewerParcelMgr::cleanupGlobals(); + LLViewerParcelMgr::cleanupGlobals(); - // *Note: this is where gViewerStats used to be deleted. + // *Note: this is where gViewerStats used to be deleted. - //end_messaging_system(); + //end_messaging_system(); - LLPrimitive::cleanupVolumeManager(); - SUBSYSTEM_CLEANUP(LLWorldMapView); - SUBSYSTEM_CLEANUP(LLFolderViewItem); + LLPrimitive::cleanupVolumeManager(); + SUBSYSTEM_CLEANUP(LLWorldMapView); + SUBSYSTEM_CLEANUP(LLFolderViewItem); - LL_INFOS() << "Saving Data" << LL_ENDL; + LL_INFOS() << "Saving Data" << LL_ENDL; - // Store the time of our current logoff - gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + // Store the time of our current logoff + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); if (LLEnvironment::instanceExists()) { - //Store environment settings if necessary + //Store environment settings if necessary LLEnvironment::getInstance()->saveToSettings(); } - // Must do this after all panels have been deleted because panels that have persistent rects - // save their rects on delete. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - - LLUIColorTable::instance().saveUserSettings(); - - // PerAccountSettingsFile should be empty if no user has been logged on. - // *FIX:Mani This should get really saved in a "logoff" mode. - if (gSavedSettings.getString("PerAccountSettingsFile").empty()) - { - LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; - } - // Only save per account settings if the previous login succeeded, otherwise - // we might end up with a cleared out settings file in case a previous login - // failed after loading per account settings. - else if (!mSavePerAccountSettings) - { - LL_INFOS() << "Not saving per-account settings; last login was not successful." << LL_ENDL; - } - else - { - gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - LL_INFOS() << "Saved settings" << LL_ENDL; - - if (LLViewerParcelAskPlay::instanceExists()) - { - LLViewerParcelAskPlay::getInstance()->saveSettings(); - } - } - - std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); - gWarningSettings.saveToFile(warnings_settings_filename, TRUE); - - // Save URL history file - LLURLHistory::saveFile("url_history.xml"); - - // save mute list. gMuteList used to also be deleted here too. - if (gAgent.isInitialized() && LLMuteList::instanceExists()) - { - LLMuteList::getInstance()->cache(gAgent.getID()); - } - - //save call log list - if (LLConversationLog::instanceExists()) - { - LLConversationLog::instance().cache(); - } - - clearSecHandler(); + // Must do this after all panels have been deleted because panels that have persistent rects + // save their rects on delete. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - if (mPurgeCacheOnExit) - { - LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); - } - - writeDebugInfo(); - - LLLocationHistory::getInstance()->save(); - - LLAvatarIconIDCache::getInstance()->save(); - - // Stop the plugin read thread if it's running. - LLPluginProcessParent::setUseReadThread(false); - - LL_INFOS() << "Shutting down Threads" << LL_ENDL; - - // Let threads finish - LLTimer idleTimer; - idleTimer.reset(); - const F64 max_idle_time = 5.f; // 5 seconds - while(1) - { - S32 pending = 0; - pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread - pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - pending += LLLFSThread::updateClass(0); - F64 idle_time = idleTimer.getElapsedTimeF64(); - if(!pending) - { - break ; //done - } - else if(idle_time >= max_idle_time) - { - LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; - break; - } - } + LLUIColorTable::instance().saveUserSettings(); - if (mPurgeUserDataOnExit) + // PerAccountSettingsFile should be empty if no user has been logged on. + // *FIX:Mani This should get really saved in a "logoff" mode. + if (gSavedSettings.getString("PerAccountSettingsFile").empty()) { - // Ideally we should not save anything from this session since it is going to be purged now, - // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code - std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); - gDirUtilp->deleteDirAndContents(user_path); + LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; } + // Only save per account settings if the previous login succeeded, otherwise + // we might end up with a cleared out settings file in case a previous login + // failed after loading per account settings. + else if (!mSavePerAccountSettings) + { + LL_INFOS() << "Not saving per-account settings; last login was not successful." << LL_ENDL; + } + else + { + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + LL_INFOS() << "Saved settings" << LL_ENDL; - // Delete workers first - // shotdown all worker threads before deleting them in case of co-dependencies - mAppCoreHttp.requestStop(); - sTextureFetch->shutdown(); - sTextureCache->shutdown(); - sImageDecodeThread->shutdown(); - sPurgeDiskCacheThread->shutdown(); - if (mGeneralThreadPool) - { - mGeneralThreadPool->close(); - } - - sTextureFetch->shutDownTextureCacheThread() ; - LLLFSThread::sLocal->shutdown(); + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->saveSettings(); + } + } - LL_INFOS() << "Shutting down message system" << LL_ENDL; - end_messaging_system(); + std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); + gWarningSettings.saveToFile(warnings_settings_filename, TRUE); - // Non-LLCurl libcurl library - mAppCoreHttp.cleanup(); + // Save URL history file + LLURLHistory::saveFile("url_history.xml"); - SUBSYSTEM_CLEANUP(LLFilePickerThread); - SUBSYSTEM_CLEANUP(LLDirPickerThread); + // save mute list. gMuteList used to also be deleted here too. + if (gAgent.isInitialized() && LLMuteList::instanceExists()) + { + LLMuteList::getInstance()->cache(gAgent.getID()); + } - //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) - delete sTextureCache; - sTextureCache = NULL; - if (sTextureFetch) + //save call log list + if (LLConversationLog::instanceExists()) + { + LLConversationLog::instance().cache(); + } + + clearSecHandler(); + + if (mPurgeCacheOnExit) + { + LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); + } + + writeDebugInfo(); + + LLLocationHistory::getInstance()->save(); + + LLAvatarIconIDCache::getInstance()->save(); + + // Stop the plugin read thread if it's running. + LLPluginProcessParent::setUseReadThread(false); + + LL_INFOS() << "Shutting down Threads" << LL_ENDL; + + // Let threads finish + LLTimer idleTimer; + idleTimer.reset(); + const F64 max_idle_time = 5.f; // 5 seconds + while(1) + { + S32 pending = 0; + pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread + pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + pending += LLLFSThread::updateClass(0); + F64 idle_time = idleTimer.getElapsedTimeF64(); + if(!pending) + { + break ; //done + } + else if(idle_time >= max_idle_time) + { + LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; + break; + } + } + + if (mPurgeUserDataOnExit) + { + // Ideally we should not save anything from this session since it is going to be purged now, + // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); + gDirUtilp->deleteDirAndContents(user_path); + } + + // Delete workers first + // shotdown all worker threads before deleting them in case of co-dependencies + mAppCoreHttp.requestStop(); + sTextureFetch->shutdown(); + sTextureCache->shutdown(); + sImageDecodeThread->shutdown(); + sPurgeDiskCacheThread->shutdown(); + if (mGeneralThreadPool) + { + mGeneralThreadPool->close(); + } + + sTextureFetch->shutDownTextureCacheThread() ; + LLLFSThread::sLocal->shutdown(); + + LL_INFOS() << "Shutting down message system" << LL_ENDL; + end_messaging_system(); + + // Non-LLCurl libcurl library + mAppCoreHttp.cleanup(); + + SUBSYSTEM_CLEANUP(LLFilePickerThread); + SUBSYSTEM_CLEANUP(LLDirPickerThread); + + //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) + delete sTextureCache; + sTextureCache = NULL; + if (sTextureFetch) { sTextureFetch->shutdown(); sTextureFetch->waitOnPending(); delete sTextureFetch; sTextureFetch = NULL; } - delete sImageDecodeThread; + delete sImageDecodeThread; sImageDecodeThread = NULL; - delete mFastTimerLogThread; - mFastTimerLogThread = NULL; - delete sPurgeDiskCacheThread; - sPurgeDiskCacheThread = NULL; + delete mFastTimerLogThread; + mFastTimerLogThread = NULL; + delete sPurgeDiskCacheThread; + sPurgeDiskCacheThread = NULL; delete mGeneralThreadPool; mGeneralThreadPool = NULL; - if (LLFastTimerView::sAnalyzePerformance) - { - LL_INFOS() << "Analyzing performance" << LL_ENDL; + if (LLFastTimerView::sAnalyzePerformance) + { + LL_INFOS() << "Analyzing performance" << LL_ENDL; - std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; - std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; - std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; + std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; + std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; + std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); - } + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); + } - SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; + SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; - LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; + LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; - //Note: - //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() - //because some new image might be generated during cleaning up media. --bao - gTextureList.shutdown(); // shutdown again in case a callback added something - LLUIImageList::getInstance()->cleanUp(); + //Note: + //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() + //because some new image might be generated during cleaning up media. --bao + gTextureList.shutdown(); // shutdown again in case a callback added something + LLUIImageList::getInstance()->cleanUp(); - SUBSYSTEM_CLEANUP(LLImage); - SUBSYSTEM_CLEANUP(LLLFSThread); + SUBSYSTEM_CLEANUP(LLImage); + SUBSYSTEM_CLEANUP(LLLFSThread); - LL_INFOS() << "Misc Cleanup" << LL_ENDL; + LL_INFOS() << "Misc Cleanup" << LL_ENDL; - gSavedSettings.cleanup(); - LLUIColorTable::instance().clear(); + gSavedSettings.cleanup(); + LLUIColorTable::instance().clear(); - LLWatchdog::getInstance()->cleanup(); + LLWatchdog::getInstance()->cleanup(); - LLViewerAssetStatsFF::cleanup(); + LLViewerAssetStatsFF::cleanup(); - // If we're exiting to launch an URL, do that here so the screen - // is at the right resolution before we launch IE. - if (!gLaunchFileOnQuit.empty()) - { - LL_INFOS() << "Launch file on quit." << LL_ENDL; + // If we're exiting to launch an URL, do that here so the screen + // is at the right resolution before we launch IE. + if (!gLaunchFileOnQuit.empty()) + { + LL_INFOS() << "Launch file on quit." << LL_ENDL; #if LL_WINDOWS - // Indicate an application is starting. - SetCursor(LoadCursor(NULL, IDC_WAIT)); + // Indicate an application is starting. + SetCursor(LoadCursor(NULL, IDC_WAIT)); #endif - // HACK: Attempt to wait until the screen res. switch is complete. - ms_sleep(1000); + // HACK: Attempt to wait until the screen res. switch is complete. + ms_sleep(1000); - LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); - LL_INFOS() << "File launched." << LL_ENDL; - } - // make sure nothing uses applyProxySettings by this point. - LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; - SUBSYSTEM_CLEANUP(LLProxy); + LLWeb::loadURLExternal( gLaunchFileOnQuit, false ); + LL_INFOS() << "File launched." << LL_ENDL; + } + // make sure nothing uses applyProxySettings by this point. + LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; + SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); - ll_close_fail_log(); + ll_close_fail_log(); - LLError::LLCallStacks::cleanup(); + LLError::LLCallStacks::cleanup(); - LLEnvironment::deleteSingleton(); - LLSelectMgr::deleteSingleton(); - LLViewerEventRecorder::deleteSingleton(); + LLEnvironment::deleteSingleton(); + LLSelectMgr::deleteSingleton(); + LLViewerEventRecorder::deleteSingleton(); LLWorld::deleteSingleton(); LLVoiceClient::deleteSingleton(); - // It's not at first obvious where, in this long sequence, a generic cleanup - // call OUGHT to go. So let's say this: as we migrate cleanup from - // explicit hand-placed calls into the generic mechanism, eventually - // all cleanup will get subsumed into the generic call. So the calls you - // still see above are calls that MUST happen before the generic cleanup - // kicks in. + // It's not at first obvious where, in this long sequence, a generic cleanup + // call OUGHT to go. So let's say this: as we migrate cleanup from + // explicit hand-placed calls into the generic mechanism, eventually + // all cleanup will get subsumed into the generic call. So the calls you + // still see above are calls that MUST happen before the generic cleanup + // kicks in. - // This calls every remaining LLSingleton's cleanupSingleton() and - // deleteSingleton() methods. - LLSingletonBase::deleteAll(); + // This calls every remaining LLSingleton's cleanupSingleton() and + // deleteSingleton() methods. + LLSingletonBase::deleteAll(); LLSplashScreen::hide(); LL_INFOS() << "Goodbye!" << LL_ENDL; - removeDumpDir(); + removeDumpDir(); - // return 0; - return true; + // return 0; + return true; } void LLAppViewer::initGeneralThread() @@ -2220,11 +2220,11 @@ void LLAppViewer::initGeneralThread() bool LLAppViewer::initThreads() { - static const bool enable_threads = true; + static const bool enable_threads = true; - LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); + LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); - LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo + LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo //auto configure thread count LLSD threadCounts = gSavedSettings.getLLSD("ThreadPoolSizes"); @@ -2239,39 +2239,39 @@ bool LLAppViewer::initThreads() } // The only configurable thread count right now is ImageDecode - // The viewer typically starts around 8 threads not including image decode, + // The viewer typically starts around 8 threads not including image decode, // so try to leave at least one core free S32 image_decode_count = llclamp(cores - 9, 1, 8); threadCounts["ImageDecode"] = image_decode_count; gSavedSettings.setLLSD("ThreadPoolSizes", threadCounts); - // Image decoding - LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); - LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); - LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), - enable_threads && true, - app_metrics_qa_mode); + // Image decoding + LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); + LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); + LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), + enable_threads && true, + app_metrics_qa_mode); // general task background thread (LLPerfStats, etc) LLAppViewer::instance()->initGeneralThread(); - LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); + LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); - if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) - { - LLTrace::BlockTimer::setLogLock(new LLMutex()); - mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); - mFastTimerLogThread->start(); - } + if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) + { + LLTrace::BlockTimer::setLogLock(new LLMutex()); + mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); + mFastTimerLogThread->start(); + } - // Mesh streaming and caching - gMeshRepo.init(); + // Mesh streaming and caching + gMeshRepo.init(); - LLFilePickerThread::initClass(); - LLDirPickerThread::initClass(); + LLFilePickerThread::initClass(); + LLDirPickerThread::initClass(); - // *FIX: no error handling here! - return true; + // *FIX: no error handling here! + return true; } void errorCallback(LLError::ELevel level, const std::string &error_string) @@ -2315,7 +2315,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() if (mSecondInstance) { LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); - + LLUUID uid; uid.generate(); LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); @@ -2386,123 +2386,123 @@ void LLAppViewer::initLoggingAndGetLastDuration() } bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults) + bool set_defaults) { - if (!mSettingsLocationList) - { - LL_ERRS() << "Invalid settings location list" << LL_ENDL; - } - - for (const SettingsGroup& group : mSettingsLocationList->groups) - { - // skip settings groups that aren't the one we requested - if (group.name() != location_key) continue; - - ELLPath path_index = (ELLPath)group.path_index(); - if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) - { - LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; - return false; - } - - for (const SettingsFile& file : group.files) - { - LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() - << " - from location " << location_key << LL_ENDL; - - auto settings_group = LLControlGroup::getInstance(file.name); - if(!settings_group) - { - LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; - continue; - } - - std::string full_settings_path; - - if (file.file_name_setting.isProvided() - && gSavedSettings.controlExists(file.file_name_setting)) - { - // try to find filename stored in file_name_setting control - full_settings_path = gSavedSettings.getString(file.file_name_setting); - if (full_settings_path.empty()) - { - continue; - } - else if (!gDirUtilp->fileExists(full_settings_path)) - { - // search in default path - full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path); - } - } - else - { - // by default, use specified file name - full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); - } - - if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) - { // success! - LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; - } - else - { // failed to load - if(file.required) - { + if (!mSettingsLocationList) + { + LL_ERRS() << "Invalid settings location list" << LL_ENDL; + } + + for (const SettingsGroup& group : mSettingsLocationList->groups) + { + // skip settings groups that aren't the one we requested + if (group.name() != location_key) continue; + + ELLPath path_index = (ELLPath)group.path_index(); + if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) + { + LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; + return false; + } + + for (const SettingsFile& file : group.files) + { + LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() + << " - from location " << location_key << LL_ENDL; + + auto settings_group = LLControlGroup::getInstance(file.name); + if(!settings_group) + { + LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; + continue; + } + + std::string full_settings_path; + + if (file.file_name_setting.isProvided() + && gSavedSettings.controlExists(file.file_name_setting)) + { + // try to find filename stored in file_name_setting control + full_settings_path = gSavedSettings.getString(file.file_name_setting); + if (full_settings_path.empty()) + { + continue; + } + else if (!gDirUtilp->fileExists(full_settings_path)) + { + // search in default path + full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path); + } + } + else + { + // by default, use specified file name + full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name()); + } + + if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent)) + { // success! + LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL; + } + else + { // failed to load + if(file.required) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; - return false; - } - else - { - // only complain if we actually have a filename at this point - if (!full_settings_path.empty()) - { - LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; - } - } - } - } - } - - return true; + LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; + return false; + } + else + { + // only complain if we actually have a filename at this point + if (!full_settings_path.empty()) + { + LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; + } + } + } + } + } + + return true; } std::string LLAppViewer::getSettingsFilename(const std::string& location_key, - const std::string& file) + const std::string& file) { - for (const SettingsGroup& group : mSettingsLocationList->groups) - { - if (group.name() == location_key) - { - for (const SettingsFile& settings_file : group.files) - { - if (settings_file.name() == file) - { - return settings_file.file_name; - } - } - } - } - - return std::string(); + for (const SettingsGroup& group : mSettingsLocationList->groups) + { + if (group.name() == location_key) + { + for (const SettingsFile& settings_file : group.files) + { + if (settings_file.name() == file) + { + return settings_file.file_name; + } + } + } + } + + return std::string(); } void LLAppViewer::loadColorSettings() { - LLUIColorTable::instance().loadFromSettings(); + LLUIColorTable::instance().loadFromSettings(); } namespace { void handleCommandLineError(LLControlGroupCLP& clp) { - LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; + LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; - LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; + LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; - OSMessageBox(STRINGIZE(LLTrans::getString("MBCmdLineError") << clp.getErrorMessage()), - LLStringUtil::null, - OSMB_OK); + OSMessageBox(STRINGIZE(LLTrans::getString("MBCmdLineError") << clp.getErrorMessage()), + LLStringUtil::null, + OSMB_OK); } } // anonymous namespace @@ -2510,42 +2510,42 @@ namespace // Name can be specified as ".", with default group being Global. bool tempSetControl(const std::string& name, const std::string& value) { - std::string name_part; - std::string group_part; - LLControlVariable* control = NULL; - - // Name can be further split into ControlGroup.Name, with the default control group being Global - size_t pos = name.find('.'); - if (pos != std::string::npos) - { - group_part = name.substr(0, pos); - name_part = name.substr(pos+1); - LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; - auto g = LLControlGroup::getInstance(group_part); - if (g) control = g->getControl(name_part); - } - else - { - LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; - control = gSavedSettings.getControl(name); - } - - if (control) - { - control->setValue(value, false); - return true; - } - return false; + std::string name_part; + std::string group_part; + LLControlVariable* control = NULL; + + // Name can be further split into ControlGroup.Name, with the default control group being Global + size_t pos = name.find('.'); + if (pos != std::string::npos) + { + group_part = name.substr(0, pos); + name_part = name.substr(pos+1); + LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; + auto g = LLControlGroup::getInstance(group_part); + if (g) control = g->getControl(name_part); + } + else + { + LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; + control = gSavedSettings.getControl(name); + } + + if (control) + { + control->setValue(value, false); + return true; + } + return false; } bool LLAppViewer::initConfiguration() { - //Load settings files list - std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); - LLXMLNodePtr root; - BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL); - if (!success) - { + //Load settings files list + std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); + LLXMLNodePtr root; + BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL); + if (!success) + { LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL; LLError::LLUserWarningMsg::showMissingFiles(); if (gDirUtilp->fileExists(settings_file_list)) @@ -2562,175 +2562,175 @@ bool LLAppViewer::initConfiguration() << "and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; } - } + } - mSettingsLocationList = new SettingsFiles(); + mSettingsLocationList = new SettingsFiles(); - LLXUIParser parser; - parser.readXUI(root, *mSettingsLocationList, settings_file_list); + LLXUIParser parser; + parser.readXUI(root, *mSettingsLocationList, settings_file_list); - if (!mSettingsLocationList->validateBlock()) - { + if (!mSettingsLocationList->validateBlock()) + { LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Invalid settings file list " << settings_file_list << LL_ENDL; - } - - // The settings and command line parsing have a fragile - // order-of-operation: - // - load defaults from app_settings - // - set procedural settings values - // - read command line settings - // - selectively apply settings needed to load user settings. + } + + // The settings and command line parsing have a fragile + // order-of-operation: + // - load defaults from app_settings + // - set procedural settings values + // - read command line settings + // - selectively apply settings needed to load user settings. // - load overrides from user_settings - // - apply command line settings (to override the overrides) - // - load per account settings (happens in llstartup - - // - load defaults - bool set_defaults = true; - if(!loadSettingsFromDirectory("Default", set_defaults)) - { - OSMessageBox( - "Unable to load default settings file. The installation may be corrupted.", - LLStringUtil::null,OSMB_OK); - return false; - } - - initStrings(); // setup paths for LLTrans based on settings files only - // - set procedural settings - // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet - gSavedSettings.setString("ClientSettingsFile", + // - apply command line settings (to override the overrides) + // - load per account settings (happens in llstartup + + // - load defaults + bool set_defaults = true; + if(!loadSettingsFromDirectory("Default", set_defaults)) + { + OSMessageBox( + "Unable to load default settings file. The installation may be corrupted.", + LLStringUtil::null,OSMB_OK); + return false; + } + + initStrings(); // setup paths for LLTrans based on settings files only + // - set procedural settings + // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet + gSavedSettings.setString("ClientSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); -#ifndef LL_RELEASE_FOR_DOWNLOAD - // provide developer build only overrides for these control variables that are not - // persisted to settings.xml - LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); - if (c) - { - c->setValue(true, false); - } - - gSavedSettings.setBOOL("QAMode", TRUE ); - gSavedSettings.setS32("WatchdogEnabled", 0); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // provide developer build only overrides for these control variables that are not + // persisted to settings.xml + LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); + if (c) + { + c->setValue(true, false); + } + + gSavedSettings.setBOOL("QAMode", TRUE ); + gSavedSettings.setS32("WatchdogEnabled", 0); #endif - // These are warnings that appear on the first experience of that condition. - // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse - // for disable/reset ability -// LLFirstUse::addConfigVariable("FirstBalanceIncrease"); -// LLFirstUse::addConfigVariable("FirstBalanceDecrease"); -// LLFirstUse::addConfigVariable("FirstSit"); -// LLFirstUse::addConfigVariable("FirstMap"); -// LLFirstUse::addConfigVariable("FirstGoTo"); -// LLFirstUse::addConfigVariable("FirstBuild"); -// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); -// LLFirstUse::addConfigVariable("FirstTeleport"); -// LLFirstUse::addConfigVariable("FirstOverrideKeys"); -// LLFirstUse::addConfigVariable("FirstAttach"); -// LLFirstUse::addConfigVariable("FirstAppearance"); -// LLFirstUse::addConfigVariable("FirstInventory"); -// LLFirstUse::addConfigVariable("FirstSandbox"); -// LLFirstUse::addConfigVariable("FirstFlexible"); -// LLFirstUse::addConfigVariable("FirstDebugMenus"); -// LLFirstUse::addConfigVariable("FirstSculptedPrim"); -// LLFirstUse::addConfigVariable("FirstVoice"); -// LLFirstUse::addConfigVariable("FirstMedia"); - - // - read command line settings. - LLControlGroupCLP clp; - std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, - "cmd_line.xml"); - - clp.configure(cmd_line_config, &gSavedSettings); - - if(!initParseCommandLine(clp)) - { - handleCommandLineError(clp); - return false; - } - - // - selectively apply settings - - // If the user has specified a alternate settings file name. - // Load it now before loading the user_settings/settings.xml - if(clp.hasOption("settings")) - { - std::string user_settings_filename = - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - clp.getOption("settings")[0]); - gSavedSettings.setString("ClientSettingsFile", user_settings_filename); - LL_INFOS("Settings") << "Using command line specified settings filename: " - << user_settings_filename << LL_ENDL; - } - - // - load overrides from user_settings - loadSettingsFromDirectory("User"); - - if (gSavedSettings.getBOOL("FirstRunThisInstall")) - { - // Set firstrun flag to indicate that some further init actiona should be taken - // like determining screen DPI value and so on - mIsFirstRun = true; - - gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); - } - - if (clp.hasOption("sessionsettings")) - { - std::string session_settings_filename = clp.getOption("sessionsettings")[0]; - gSavedSettings.setString("SessionSettingsFile", session_settings_filename); - LL_INFOS("Settings") << "Using session settings filename: " - << session_settings_filename << LL_ENDL; - } - loadSettingsFromDirectory("Session"); - - if (clp.hasOption("usersessionsettings")) - { - std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0]; - gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename); - LL_INFOS("Settings") << "Using user session settings filename: " - << user_session_settings_filename << LL_ENDL; - - } - loadSettingsFromDirectory("UserSession"); - - // - apply command line settings - if (! clp.notify()) - { - handleCommandLineError(clp); - return false; - } - - // Register the core crash option as soon as we can - // if we want gdb post-mortem on cores we need to be up and running - // ASAP or we might miss init issue etc. - if(gSavedSettings.getBOOL("DisableCrashLogger")) - { - LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << LL_ENDL; - disableCrashlogger(); - } - - gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); - // Handle initialization from settings. - // Start up the debugging console before handling other options. - if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) - { - initConsole(); - } - - if(clp.hasOption("help")) - { - std::ostringstream msg; - msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; - LL_INFOS() << msg.str() << LL_ENDL; - - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - - return false; - } + // These are warnings that appear on the first experience of that condition. + // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse + // for disable/reset ability +// LLFirstUse::addConfigVariable("FirstBalanceIncrease"); +// LLFirstUse::addConfigVariable("FirstBalanceDecrease"); +// LLFirstUse::addConfigVariable("FirstSit"); +// LLFirstUse::addConfigVariable("FirstMap"); +// LLFirstUse::addConfigVariable("FirstGoTo"); +// LLFirstUse::addConfigVariable("FirstBuild"); +// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); +// LLFirstUse::addConfigVariable("FirstTeleport"); +// LLFirstUse::addConfigVariable("FirstOverrideKeys"); +// LLFirstUse::addConfigVariable("FirstAttach"); +// LLFirstUse::addConfigVariable("FirstAppearance"); +// LLFirstUse::addConfigVariable("FirstInventory"); +// LLFirstUse::addConfigVariable("FirstSandbox"); +// LLFirstUse::addConfigVariable("FirstFlexible"); +// LLFirstUse::addConfigVariable("FirstDebugMenus"); +// LLFirstUse::addConfigVariable("FirstSculptedPrim"); +// LLFirstUse::addConfigVariable("FirstVoice"); +// LLFirstUse::addConfigVariable("FirstMedia"); + + // - read command line settings. + LLControlGroupCLP clp; + std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, + "cmd_line.xml"); + + clp.configure(cmd_line_config, &gSavedSettings); + + if(!initParseCommandLine(clp)) + { + handleCommandLineError(clp); + return false; + } + + // - selectively apply settings + + // If the user has specified a alternate settings file name. + // Load it now before loading the user_settings/settings.xml + if(clp.hasOption("settings")) + { + std::string user_settings_filename = + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + clp.getOption("settings")[0]); + gSavedSettings.setString("ClientSettingsFile", user_settings_filename); + LL_INFOS("Settings") << "Using command line specified settings filename: " + << user_settings_filename << LL_ENDL; + } + + // - load overrides from user_settings + loadSettingsFromDirectory("User"); + + if (gSavedSettings.getBOOL("FirstRunThisInstall")) + { + // Set firstrun flag to indicate that some further init actiona should be taken + // like determining screen DPI value and so on + mIsFirstRun = true; + + gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); + } + + if (clp.hasOption("sessionsettings")) + { + std::string session_settings_filename = clp.getOption("sessionsettings")[0]; + gSavedSettings.setString("SessionSettingsFile", session_settings_filename); + LL_INFOS("Settings") << "Using session settings filename: " + << session_settings_filename << LL_ENDL; + } + loadSettingsFromDirectory("Session"); + + if (clp.hasOption("usersessionsettings")) + { + std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0]; + gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename); + LL_INFOS("Settings") << "Using user session settings filename: " + << user_session_settings_filename << LL_ENDL; + + } + loadSettingsFromDirectory("UserSession"); + + // - apply command line settings + if (! clp.notify()) + { + handleCommandLineError(clp); + return false; + } + + // Register the core crash option as soon as we can + // if we want gdb post-mortem on cores we need to be up and running + // ASAP or we might miss init issue etc. + if(gSavedSettings.getBOOL("DisableCrashLogger")) + { + LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << LL_ENDL; + disableCrashlogger(); + } + + gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); + // Handle initialization from settings. + // Start up the debugging console before handling other options. + if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) + { + initConsole(); + } + + if(clp.hasOption("help")) + { + std::ostringstream msg; + msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; + LL_INFOS() << msg.str() << LL_ENDL; + + OSMessageBox( + msg.str(), + LLStringUtil::null, + OSMB_OK); + + return false; + } if(clp.hasOption("set")) { @@ -2748,43 +2748,43 @@ bool LLAppViewer::initConfiguration() const std::string& value = *(++itr); if (!tempSetControl(name,value)) { - LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; + LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; } } } } if (clp.hasOption("logevents")) { - LLViewerEventRecorder::instance().setEventLoggingOn(); + LLViewerEventRecorder::instance().setEventLoggingOn(); } - std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); - if(! CmdLineChannel.empty()) + std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); + if(! CmdLineChannel.empty()) { - LLVersionInfo::instance().resetChannel(CmdLineChannel); - } + LLVersionInfo::instance().resetChannel(CmdLineChannel); + } - // If we have specified crash on startup, set the global so we'll trigger the crash at the right time - gCrashOnStartup = gSavedSettings.getBOOL("CrashOnStartup"); + // If we have specified crash on startup, set the global so we'll trigger the crash at the right time + gCrashOnStartup = gSavedSettings.getBOOL("CrashOnStartup"); - if (gSavedSettings.getBOOL("LogPerformance")) - { - LLTrace::BlockTimer::sLog = true; - LLTrace::BlockTimer::sLogName = std::string("performance"); - } + if (gSavedSettings.getBOOL("LogPerformance")) + { + LLTrace::BlockTimer::sLog = true; + LLTrace::BlockTimer::sLogName = std::string("performance"); + } - std::string test_name(gSavedSettings.getString("LogMetrics")); - if (! test_name.empty()) - { - LLTrace::BlockTimer::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...) - LL_INFOS() << "'--logmetrics' argument : " << test_name << LL_ENDL; - LLTrace::BlockTimer::sLogName = test_name; - } + std::string test_name(gSavedSettings.getString("LogMetrics")); + if (! test_name.empty()) + { + LLTrace::BlockTimer::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...) + LL_INFOS() << "'--logmetrics' argument : " << test_name << LL_ENDL; + LLTrace::BlockTimer::sLogName = test_name; + } - if (clp.hasOption("graphicslevel")) - { + if (clp.hasOption("graphicslevel")) + { // User explicitly requested --graphicslevel on the command line. We // expect this switch has already set RenderQualityPerformance. Check // that value for validity later. @@ -2793,18 +2793,18 @@ bool LLAppViewer::initConfiguration() // will call LLFeatureManager::applyRecommendedSettings(), which // overwrites this settings variable! mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance"); - } + } - LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); - gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); + LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); + gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); - if (gSavedSettings.getBOOL("DebugSession")) - { - gDebugSession = TRUE; - gDebugGL = TRUE; + if (gSavedSettings.getBOOL("DebugSession")) + { + gDebugSession = TRUE; + gDebugGL = TRUE; - ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); - } + ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); + } if (gSavedSettings.getBOOL("RenderDebugGLSession")) { @@ -2815,47 +2815,47 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setBOOL("RenderDebugGLSession", FALSE); } - const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); - if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) - { - // Examining "Language" may not suffice -- see LLUI::getLanguage() - // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much - // good because we haven't yet called LLUI::initClass(). - gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), - gSavedSettings.getString("Language")); - } - - if (gSavedSettings.getBOOL("SpellCheck")) - { - std::list dict_list; - std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); - boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); - if (!dict_list.empty()) - { - LLSpellChecker::setUseSpellCheck(dict_list.front()); - dict_list.pop_front(); - LLSpellChecker::instance().setSecondaryDictionaries(dict_list); - } - } - - if (gNonInteractive) - { - tempSetControl("AllowMultipleViewers", "TRUE"); - tempSetControl("SLURLPassToOtherInstance", "FALSE"); - tempSetControl("RenderWater", "FALSE"); - tempSetControl("FlyingAtExit", "FALSE"); - tempSetControl("WindowWidth", "1024"); - tempSetControl("WindowHeight", "200"); - LLError::setEnabledLogTypesMask(0); - llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); - } - - - // Handle slurl use. NOTE: Don't let SL-55321 reappear. - // This initial-SLURL logic, up through the call to - // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- - // because if sendURLToOtherInstance() succeeds, we take a fast exit, - // SKIPPING the splash screen and everything else. + const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); + if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) + { + // Examining "Language" may not suffice -- see LLUI::getLanguage() + // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much + // good because we haven't yet called LLUI::initClass(). + gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), + gSavedSettings.getString("Language")); + } + + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list dict_list; + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + } + } + + if (gNonInteractive) + { + tempSetControl("AllowMultipleViewers", "TRUE"); + tempSetControl("SLURLPassToOtherInstance", "FALSE"); + tempSetControl("RenderWater", "FALSE"); + tempSetControl("FlyingAtExit", "FALSE"); + tempSetControl("WindowWidth", "1024"); + tempSetControl("WindowHeight", "200"); + LLError::setEnabledLogTypesMask(0); + llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); + } + + + // Handle slurl use. NOTE: Don't let SL-55321 reappear. + // This initial-SLURL logic, up through the call to + // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- + // because if sendURLToOtherInstance() succeeds, we take a fast exit, + // SKIPPING the splash screen and everything else. // *FIX: This init code should be made more robust to prevent // the issue SL-55321 from returning. One thought is to allow @@ -2873,143 +2873,143 @@ bool LLAppViewer::initConfiguration() // other browsers) and do the rough equivalent of command // injection and steal passwords. Phoenix. SL-55321 - std::string starting_location; - - std::string cmd_line_login_location(gSavedSettings.getString("CmdLineLoginLocation")); - if(! cmd_line_login_location.empty()) - { - starting_location = cmd_line_login_location; - } - else - { - std::string default_login_location(gSavedSettings.getString("DefaultLoginLocation")); - if (! default_login_location.empty()) - { - starting_location = default_login_location; - } - } - - LLSLURL start_slurl; - if (! starting_location.empty()) - { - start_slurl = starting_location; - LLStartUp::setStartSLURL(start_slurl); - if(start_slurl.getType() == LLSLURL::LOCATION) - { - LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); - } - } - - // NextLoginLocation is set as a side effect of LLStartUp::setStartSLURL() - std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); - if ( !nextLoginLocation.empty() ) - { - LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<useMutex(); // LLApp and LLMutex magic must be manually enabled - LLPrimitive::setVolumeManager(volume_manager); - - // Note: this is where we used to initialize gFeatureManagerp. - - gStartTime = totalTime(); - - // - // Set the name of the window - // - gWindowTitle = LLTrans::getString("APP_NAME"); + std::string starting_location; + + std::string cmd_line_login_location(gSavedSettings.getString("CmdLineLoginLocation")); + if(! cmd_line_login_location.empty()) + { + starting_location = cmd_line_login_location; + } + else + { + std::string default_login_location(gSavedSettings.getString("DefaultLoginLocation")); + if (! default_login_location.empty()) + { + starting_location = default_login_location; + } + } + + LLSLURL start_slurl; + if (! starting_location.empty()) + { + start_slurl = starting_location; + LLStartUp::setStartSLURL(start_slurl); + if(start_slurl.getType() == LLSLURL::LOCATION) + { + LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid()); + } + } + + // NextLoginLocation is set as a side effect of LLStartUp::setStartSLURL() + std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); + if ( !nextLoginLocation.empty() ) + { + LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<useMutex(); // LLApp and LLMutex magic must be manually enabled + LLPrimitive::setVolumeManager(volume_manager); + + // Note: this is where we used to initialize gFeatureManagerp. + + gStartTime = totalTime(); + + // + // Set the name of the window + // + gWindowTitle = LLTrans::getString("APP_NAME"); #if LL_DEBUG - gWindowTitle += std::string(" [DEBUG]"); + gWindowTitle += std::string(" [DEBUG]"); #endif - if (!gArgs.empty()) - { - gWindowTitle += std::string(" ") + gArgs; - } - LLStringUtil::truncate(gWindowTitle, 255); - - // - // Check for another instance of the app running - // This happens AFTER LLSplashScreen::show(). That may or may not be - // important. - // - if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) - { - OSMessageBox( - LLTrans::getString("MBAlreadyRunning"), - LLStringUtil::null, - OSMB_OK); - return false; - } - - if (mSecondInstance) - { - // This is the second instance of SL. Mute voice, - // but make sure the setting is *not* persisted. - // Also see LLVivoxVoiceClient::voiceEnabled() - LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); - if(enable_voice) - { - const BOOL DO_NOT_PERSIST = FALSE; - enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); - } - } - - gLastRunVersion = gSavedSettings.getString("LastRunVersion"); - - loadColorSettings(); - - // Let anyone else who cares know that we've populated our settings - // variables. - for (const auto& key : LLControlGroup::key_snapshot()) - { - // For each named instance of LLControlGroup, send an event saying - // we've initialized an LLControlGroup instance by that name. - LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); - } + if (!gArgs.empty()) + { + gWindowTitle += std::string(" ") + gArgs; + } + LLStringUtil::truncate(gWindowTitle, 255); + + // + // Check for another instance of the app running + // This happens AFTER LLSplashScreen::show(). That may or may not be + // important. + // + if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) + { + OSMessageBox( + LLTrans::getString("MBAlreadyRunning"), + LLStringUtil::null, + OSMB_OK); + return false; + } + + if (mSecondInstance) + { + // This is the second instance of SL. Mute voice, + // but make sure the setting is *not* persisted. + // Also see LLVivoxVoiceClient::voiceEnabled() + LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat"); + if(enable_voice) + { + const BOOL DO_NOT_PERSIST = FALSE; + enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST); + } + } + + gLastRunVersion = gSavedSettings.getString("LastRunVersion"); + + loadColorSettings(); + + // Let anyone else who cares know that we've populated our settings + // variables. + for (const auto& key : LLControlGroup::key_snapshot()) + { + // For each named instance of LLControlGroup, send an event saying + // we've initialized an LLControlGroup instance by that name. + LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); + } LLError::LLUserWarningMsg::setOutOfMemoryStrings(LLTrans::getString("MBOutOfMemoryTitle"), LLTrans::getString("MBOutOfMemoryErr")); - return true; // Config was successful. + return true; // Config was successful. } // The following logic is replicated in initConfiguration() (to be able to get @@ -3018,214 +3018,214 @@ bool LLAppViewer::initConfiguration() // keeps growing, necessitating a method all its own. void LLAppViewer::initStrings() { - std::string strings_file = "strings.xml"; - std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); - if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) - { - if (strings_path_full.empty()) - { - LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; - } - else - { - llstat st; - int rc = LLFile::stat(strings_path_full, &st); - if (rc != 0) - { - LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; - } - else if (S_ISDIR(st.st_mode)) - { - LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; - } - else - { - LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; - } - } - - // initial check to make sure files are there failed - gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); + std::string strings_file = "strings.xml"; + std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file); + if (strings_path_full.empty() || !LLFile::isfile(strings_path_full)) + { + if (strings_path_full.empty()) + { + LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL; + } + else + { + llstat st; + int rc = LLFile::stat(strings_path_full, &st); + if (rc != 0) + { + LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL; + } + else if (S_ISDIR(st.st_mode)) + { + LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL; + } + else + { + LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL; + } + } + + // initial check to make sure files are there failed + gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Viewer failed to find localization and UI files." - << " Please reinstall viewer from https://secondlife.com/support/downloads" - << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; - } - LLTransUtil::parseStrings(strings_file, default_trans_args); - LLTransUtil::parseLanguageStrings("language_settings.xml"); - - // parseStrings() sets up the LLTrans substitution table. Add this one item. - LLTrans::setDefaultArg("[sourceid]", gSavedSettings.getString("sourceid")); - - // Now that we've set "[sourceid]", have to go back through - // default_trans_args and reinitialize all those other keys because some - // of them, in turn, reference "[sourceid]". - for (const std::string& key : default_trans_args) - { - std::string brackets(key), nobrackets(key); - // Invalid to inspect key[0] if key is empty(). But then, the entire - // body of this loop is pointless if key is empty(). - if (key.empty()) - continue; - - if (key[0] != '[') - { - // key was passed without brackets. That means that 'nobrackets' - // is correct but 'brackets' is not. - brackets = STRINGIZE('[' << brackets << ']'); - } - else - { - // key was passed with brackets. That means that 'brackets' is - // correct but 'nobrackets' is not. Erase the left bracket. - nobrackets.erase(0, 1); - std::string::size_type length(nobrackets.length()); - if (length && nobrackets[length - 1] == ']') - { - nobrackets.erase(length - 1); - } - } - // Calling LLTrans::getString() is what embeds the other default - // translation strings into this one. - LLTrans::setDefaultArg(brackets, LLTrans::getString(nobrackets)); - } + LL_ERRS() << "Viewer failed to find localization and UI files." + << " Please reinstall viewer from https://secondlife.com/support/downloads" + << " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL; + } + LLTransUtil::parseStrings(strings_file, default_trans_args); + LLTransUtil::parseLanguageStrings("language_settings.xml"); + + // parseStrings() sets up the LLTrans substitution table. Add this one item. + LLTrans::setDefaultArg("[sourceid]", gSavedSettings.getString("sourceid")); + + // Now that we've set "[sourceid]", have to go back through + // default_trans_args and reinitialize all those other keys because some + // of them, in turn, reference "[sourceid]". + for (const std::string& key : default_trans_args) + { + std::string brackets(key), nobrackets(key); + // Invalid to inspect key[0] if key is empty(). But then, the entire + // body of this loop is pointless if key is empty(). + if (key.empty()) + continue; + + if (key[0] != '[') + { + // key was passed without brackets. That means that 'nobrackets' + // is correct but 'brackets' is not. + brackets = STRINGIZE('[' << brackets << ']'); + } + else + { + // key was passed with brackets. That means that 'brackets' is + // correct but 'nobrackets' is not. Erase the left bracket. + nobrackets.erase(0, 1); + std::string::size_type length(nobrackets.length()); + if (length && nobrackets[length - 1] == ']') + { + nobrackets.erase(length - 1); + } + } + // Calling LLTrans::getString() is what embeds the other default + // translation strings into this one. + LLTrans::setDefaultArg(brackets, LLTrans::getString(nobrackets)); + } } bool LLAppViewer::meetsRequirementsForMaximizedStart() { bool maximizedOk = (gSysMemory.getPhysicalMemoryKB() >= U32Gigabytes(1)); - return maximizedOk; + return maximizedOk; } bool LLAppViewer::initWindow() { - LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; - - // store setting in a global for easy access and modification - gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); - - // always start windowed - BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); - - LLViewerWindow::Params window_params; - window_params - .title(gWindowTitle) - .name(VIEWER_WINDOW_CLASSNAME) - .x(gSavedSettings.getS32("WindowX")) - .y(gSavedSettings.getS32("WindowY")) - .width(gSavedSettings.getU32("WindowWidth")) - .height(gSavedSettings.getU32("WindowHeight")) - .min_width(gSavedSettings.getU32("MinWindowWidth")) - .min_height(gSavedSettings.getU32("MinWindowHeight")) - .fullscreen(gSavedSettings.getBOOL("FullScreen")) - .ignore_pixel_depth(ignorePixelDepth) - .first_run(mIsFirstRun); - - gViewerWindow = new LLViewerWindow(window_params); - - LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL; - - // Need to load feature table before cheking to start watchdog. - bool use_watchdog = false; - int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled"); - if (watchdog_enabled_setting == -1) - { - use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled"); - } - else - { - // The user has explicitly set this setting; always use that value. - use_watchdog = bool(watchdog_enabled_setting); - } - - LL_INFOS("AppInit") << "watchdog" - << (use_watchdog ? " " : " NOT ") - << "enabled" - << " (setting = " << watchdog_enabled_setting << ")" - << LL_ENDL; - - if (use_watchdog) - { - LLWatchdog::getInstance()->init(); - } - - LLNotificationsUI::LLNotificationManager::getInstance(); + LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; + + // store setting in a global for easy access and modification + gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient"); + + // always start windowed + BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth"); + + LLViewerWindow::Params window_params; + window_params + .title(gWindowTitle) + .name(VIEWER_WINDOW_CLASSNAME) + .x(gSavedSettings.getS32("WindowX")) + .y(gSavedSettings.getS32("WindowY")) + .width(gSavedSettings.getU32("WindowWidth")) + .height(gSavedSettings.getU32("WindowHeight")) + .min_width(gSavedSettings.getU32("MinWindowWidth")) + .min_height(gSavedSettings.getU32("MinWindowHeight")) + .fullscreen(gSavedSettings.getBOOL("FullScreen")) + .ignore_pixel_depth(ignorePixelDepth) + .first_run(mIsFirstRun); + + gViewerWindow = new LLViewerWindow(window_params); + + LL_INFOS("AppInit") << "gViewerwindow created." << LL_ENDL; + + // Need to load feature table before cheking to start watchdog. + bool use_watchdog = false; + int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled"); + if (watchdog_enabled_setting == -1) + { + use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled"); + } + else + { + // The user has explicitly set this setting; always use that value. + use_watchdog = bool(watchdog_enabled_setting); + } + + LL_INFOS("AppInit") << "watchdog" + << (use_watchdog ? " " : " NOT ") + << "enabled" + << " (setting = " << watchdog_enabled_setting << ")" + << LL_ENDL; + + if (use_watchdog) + { + LLWatchdog::getInstance()->init(); + } + + LLNotificationsUI::LLNotificationManager::getInstance(); #ifdef LL_DARWIN - //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) - LLOSInfo& os_info = LLOSInfo::instance(); - if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) - { - if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) - gViewerWindow->getWindow()->setOldResize(true); - } + //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) + LLOSInfo& os_info = LLOSInfo::instance(); + if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) + { + if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) + gViewerWindow->getWindow()->setOldResize(true); + } #endif - if (gSavedSettings.getBOOL("WindowMaximized")) - { - gViewerWindow->getWindow()->maximize(); - } + if (gSavedSettings.getBOOL("WindowMaximized")) + { + gViewerWindow->getWindow()->maximize(); + } - // - // Initialize GL stuff - // + // + // Initialize GL stuff + // - if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) - { - LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false); - gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel); - } + if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) + { + 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 ); + // Set this flag in case we crash while initializing GL + gSavedSettings.setBOOL("RenderInitError", TRUE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - gPipeline.init(); - LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; + gPipeline.init(); + LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; - stop_glerror(); - gViewerWindow->initGLDefaults(); + stop_glerror(); + gViewerWindow->initGLDefaults(); - gSavedSettings.setBOOL("RenderInitError", FALSE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); + gSavedSettings.setBOOL("RenderInitError", FALSE); + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - //If we have a startup crash, it's usually near GL initialization, so simulate that. - if(gCrashOnStartup) - { - LLAppViewer::instance()->forceErrorLLError(); - } + //If we have a startup crash, it's usually near GL initialization, so simulate that. + if(gCrashOnStartup) + { + LLAppViewer::instance()->forceErrorLLError(); + } - // - // Determine if the window should start maximized on initial run based - // on graphics capability - // - if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart()) - { - LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL; - gSavedSettings.setBOOL("WindowMaximized", TRUE); - } + // + // Determine if the window should start maximized on initial run based + // on graphics capability + // + if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart()) + { + LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL; + gSavedSettings.setBOOL("WindowMaximized", TRUE); + } - if (gSavedSettings.getBOOL("WindowMaximized")) - { - gViewerWindow->getWindow()->maximize(); - } + if (gSavedSettings.getBOOL("WindowMaximized")) + { + gViewerWindow->getWindow()->maximize(); + } - LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); + LLUI::getInstance()->mWindow = gViewerWindow->getWindow(); - // Show watch cursor - gViewerWindow->setCursor(UI_CURSOR_WAIT); + // Show watch cursor + gViewerWindow->setCursor(UI_CURSOR_WAIT); - // Finish view initialization - gViewerWindow->initBase(); + // Finish view initialization + gViewerWindow->initBase(); - // show viewer window - //gViewerWindow->getWindow()->show(); + // show viewer window + //gViewerWindow->getWindow()->show(); - LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; + LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; - return true; + return true; } bool LLAppViewer::isUpdaterMissing() @@ -3264,28 +3264,28 @@ void LLAppViewer::writeDebugInfo(bool isStatic) LLSD LLAppViewer::getViewerInfo() const { - // The point of having one method build an LLSD info block and the other - // construct the user-visible About string is to ensure that the same info - // is available to a getInfo() caller as to the user opening - // LLFloaterAbout. - LLSD info; - auto& versionInfo(LLVersionInfo::instance()); - // With GitHub builds, the build number is too big to fit in a 32-bit int, - // and LLSD doesn't deal with integers wider than int. Use string. - info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), - versionInfo.getPatch(), stringize(versionInfo.getBuild())); - info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); - info["CHANNEL"] = versionInfo.getChannel(); - info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = versionInfo.getBuildConfig(); - if (build_config != "Release") - { - info["BUILD_CONFIG"] = build_config; - } - - // return a URL to the release notes for this viewer, such as: - // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html - std::string url = versionInfo.getReleaseNotes(); // VVM supplied + // The point of having one method build an LLSD info block and the other + // construct the user-visible About string is to ensure that the same info + // is available to a getInfo() caller as to the user opening + // LLFloaterAbout. + LLSD info; + auto& versionInfo(LLVersionInfo::instance()); + // With GitHub builds, the build number is too big to fit in a 32-bit int, + // and LLSD doesn't deal with integers wider than int. Use string. + info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), + versionInfo.getPatch(), stringize(versionInfo.getBuild())); + info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); + info["CHANNEL"] = versionInfo.getChannel(); + info["ADDRESS_SIZE"] = ADDRESS_SIZE; + std::string build_config = versionInfo.getBuildConfig(); + if (build_config != "Release") + { + info["BUILD_CONFIG"] = build_config; + } + + // return a URL to the release notes for this viewer, such as: + // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html + std::string url = versionInfo.getReleaseNotes(); // VVM supplied if (url.empty()) { url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); @@ -3293,32 +3293,32 @@ LLSD LLAppViewer::getViewerInfo() const url += "/"; url += LLURI::escape(versionInfo.getVersion()) + ".html"; } - info["VIEWER_RELEASE_NOTES_URL"] = url; - - // Position - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - LLVector3d pos = gAgent.getPositionGlobal(); - info["POSITION"] = ll_sd_from_vector3d(pos); - info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); - - boost::regex regex("\\.(secondlife|lindenlab)\\..*"); - info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); - info["SERVER_VERSION"] = gLastVersionChannel; - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - info["SLURL"] = slurl.getSLURLString(); - } - - // CPU - info["CPU"] = gSysCPU.getCPUString(); - info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits()); - // Moved hack adjustment to Windows memory size into llsys.cpp - info["OS_VERSION"] = LLOSInfo::instance().getOSString(); - info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); - info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); + info["VIEWER_RELEASE_NOTES_URL"] = url; + + // Position + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLVector3d pos = gAgent.getPositionGlobal(); + info["POSITION"] = ll_sd_from_vector3d(pos); + info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); + info["REGION"] = gAgent.getRegion()->getName(); + + boost::regex regex("\\.(secondlife|lindenlab)\\..*"); + info["HOSTNAME"] = boost::regex_replace(gAgent.getRegion()->getSimHostName(), regex, ""); + info["SERVER_VERSION"] = gLastVersionChannel; + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + info["SLURL"] = slurl.getSLURLString(); + } + + // CPU + info["CPU"] = gSysCPU.getCPUString(); + info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits()); + // Moved hack adjustment to Windows memory size into llsys.cpp + info["OS_VERSION"] = LLOSInfo::instance().getOSString(); + info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR))); + info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); #if LL_WINDOWS std::string drvinfo; @@ -3343,22 +3343,22 @@ LLSD LLAppViewer::getViewerInfo() const drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_ANY); } - if (!drvinfo.empty()) - { - info["GRAPHICS_DRIVER_VERSION"] = drvinfo; - } - else - { - LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; - LLSD driver_info = gDXHardware.getDisplayInfo(); - if (driver_info.has("DriverVersion")) - { - info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; - } - } + if (!drvinfo.empty()) + { + info["GRAPHICS_DRIVER_VERSION"] = drvinfo; + } + else + { + LL_WARNS("DriverVersion")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; + LLSD driver_info = gDXHardware.getDisplayInfo(); + if (driver_info.has("DriverVersion")) + { + info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; + } + } #endif - info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); + info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); // Settings @@ -3377,16 +3377,16 @@ LLSD LLAppViewer::getViewerInfo() const info["HIDPI"] = gHiDPISupport; #endif - // Libraries + // Libraries - info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); - bool want_fullname = true; - info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined"; - if(LLVoiceClient::getInstance()->voiceEnabled()) - { + info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); + bool want_fullname = true; + info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : "Undefined"; + if(LLVoiceClient::getInstance()->voiceEnabled()) + { LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion(); const std::string build_version = version.mBuildVersion; - std::ostringstream version_string; + std::ostringstream version_string; if (std::equal(build_version.begin(), build_version.begin() + version.serverVersion.size(), version.serverVersion.begin())) { // Normal case: Show type and build version. @@ -3396,210 +3396,210 @@ LLSD LLAppViewer::getViewerInfo() const { // Mismatch: Show both versions. version_string << version.serverVersion << "/" << build_version << std::endl; } - info["VOICE_VERSION"] = version_string.str(); - } - else - { - info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); - } + info["VOICE_VERSION"] = version_string.str(); + } + else + { + info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); + } #if !LL_LINUX - std::ostringstream cef_ver_codec; - cef_ver_codec << "Dullahan: "; - cef_ver_codec << DULLAHAN_VERSION_MAJOR; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_MINOR; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_POINT; - cef_ver_codec << "."; - cef_ver_codec << DULLAHAN_VERSION_BUILD; - - cef_ver_codec << std::endl; - cef_ver_codec << " CEF: "; - cef_ver_codec << CEF_VERSION; - - cef_ver_codec << std::endl; - cef_ver_codec << " Chromium: "; - cef_ver_codec << CHROME_VERSION_MAJOR; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_MINOR; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_BUILD; - cef_ver_codec << "."; - cef_ver_codec << CHROME_VERSION_PATCH; - - info["LIBCEF_VERSION"] = cef_ver_codec.str(); + std::ostringstream cef_ver_codec; + cef_ver_codec << "Dullahan: "; + cef_ver_codec << DULLAHAN_VERSION_MAJOR; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_MINOR; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_POINT; + cef_ver_codec << "."; + cef_ver_codec << DULLAHAN_VERSION_BUILD; + + cef_ver_codec << std::endl; + cef_ver_codec << " CEF: "; + cef_ver_codec << CEF_VERSION; + + cef_ver_codec << std::endl; + cef_ver_codec << " Chromium: "; + cef_ver_codec << CHROME_VERSION_MAJOR; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_MINOR; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_BUILD; + cef_ver_codec << "."; + cef_ver_codec << CHROME_VERSION_PATCH; + + info["LIBCEF_VERSION"] = cef_ver_codec.str(); #else - info["LIBCEF_VERSION"] = "Undefined"; + info["LIBCEF_VERSION"] = "Undefined"; #endif #if !LL_LINUX - std::ostringstream vlc_ver_codec; - vlc_ver_codec << LIBVLC_VERSION_MAJOR; - vlc_ver_codec << "."; - vlc_ver_codec << LIBVLC_VERSION_MINOR; - vlc_ver_codec << "."; - vlc_ver_codec << LIBVLC_VERSION_REVISION; - info["LIBVLC_VERSION"] = vlc_ver_codec.str(); + std::ostringstream vlc_ver_codec; + vlc_ver_codec << LIBVLC_VERSION_MAJOR; + vlc_ver_codec << "."; + vlc_ver_codec << LIBVLC_VERSION_MINOR; + vlc_ver_codec << "."; + vlc_ver_codec << LIBVLC_VERSION_REVISION; + info["LIBVLC_VERSION"] = vlc_ver_codec.str(); #else - info["LIBVLC_VERSION"] = "Undefined"; + info["LIBVLC_VERSION"] = "Undefined"; #endif - S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); - if (packets_in > 0) - { - info["PACKETS_LOST"] = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_LOST); - info["PACKETS_IN"] = packets_in; - info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); - } - - if (mServerReleaseNotesURL.empty()) - { - if (gAgent.getRegion()) - { - info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("RetrievingData"); - } - else - { - info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("NotConnected"); - } - } - else if (LLStringUtil::startsWith(mServerReleaseNotesURL, "http")) // it's an URL - { - info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(mServerReleaseNotesURL) + " " + LLTrans::getString("ReleaseNotes") + "]"; - } - else - { - info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; - } + S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); + if (packets_in > 0) + { + info["PACKETS_LOST"] = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_LOST); + info["PACKETS_IN"] = packets_in; + info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); + } + + if (mServerReleaseNotesURL.empty()) + { + if (gAgent.getRegion()) + { + info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("RetrievingData"); + } + else + { + info["SERVER_RELEASE_NOTES_URL"] = LLTrans::getString("NotConnected"); + } + } + else if (LLStringUtil::startsWith(mServerReleaseNotesURL, "http")) // it's an URL + { + info["SERVER_RELEASE_NOTES_URL"] = "[" + LLWeb::escapeURL(mServerReleaseNotesURL) + " " + LLTrans::getString("ReleaseNotes") + "]"; + } + else + { + info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; + } // populate field for new local disk cache with some details info["DISK_CACHE_INFO"] = LLDiskCache::getInstance()->getCacheInfo(); - return info; + return info; } std::string LLAppViewer::getViewerInfoString(bool default_string) const { - std::ostringstream support; - - LLSD info(getViewerInfo()); - - // Render the LLSD from getInfo() as a format_map_t - LLStringUtil::format_map_t args; - - // allow the "Release Notes" URL label to be localized - args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes", default_string); - - for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap()); - ii != iend; ++ii) - { - if (! ii->second.isArray()) - { - // Scalar value - if (ii->second.isUndefined()) - { - args[ii->first] = LLTrans::getString("none_text", default_string); - } - else - { - // don't forget to render value asString() - args[ii->first] = ii->second.asString(); - } - } - else - { - // array value: build KEY_0, KEY_1 etc. entries - for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n) - { - args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString(); - } - } - } - - // Now build the various pieces - support << LLTrans::getString("AboutHeader", args, default_string); - if (info.has("BUILD_CONFIG")) - { - support << "\n" << LLTrans::getString("BuildConfig", args, default_string); - } - if (info.has("REGION")) - { - support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); - } - support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); - support << "\n"; - if (info.has("GRAPHICS_DRIVER_VERSION")) - { - support << "\n" << LLTrans::getString("AboutDriver", args, default_string); - } - support << "\n" << LLTrans::getString("AboutOGL", args, default_string); - support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string); + std::ostringstream support; + + LLSD info(getViewerInfo()); + + // Render the LLSD from getInfo() as a format_map_t + LLStringUtil::format_map_t args; + + // allow the "Release Notes" URL label to be localized + args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes", default_string); + + for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap()); + ii != iend; ++ii) + { + if (! ii->second.isArray()) + { + // Scalar value + if (ii->second.isUndefined()) + { + args[ii->first] = LLTrans::getString("none_text", default_string); + } + else + { + // don't forget to render value asString() + args[ii->first] = ii->second.asString(); + } + } + else + { + // array value: build KEY_0, KEY_1 etc. entries + for (LLSD::Integer n(0), size(ii->second.size()); n < size; ++n) + { + args[STRINGIZE(ii->first << '_' << n)] = ii->second[n].asString(); + } + } + } + + // Now build the various pieces + support << LLTrans::getString("AboutHeader", args, default_string); + if (info.has("BUILD_CONFIG")) + { + support << "\n" << LLTrans::getString("BuildConfig", args, default_string); + } + if (info.has("REGION")) + { + support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); + } + support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); + support << "\n"; + if (info.has("GRAPHICS_DRIVER_VERSION")) + { + support << "\n" << LLTrans::getString("AboutDriver", args, default_string); + } + support << "\n" << LLTrans::getString("AboutOGL", args, default_string); + support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string); #if LL_DARWIN - support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string); + support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string); #endif - support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string); - if (info.has("COMPILER")) - { - support << "\n" << LLTrans::getString("AboutCompiler", args, default_string); - } - if (info.has("PACKETS_IN")) - { - support << '\n' << LLTrans::getString("AboutTraffic", args, default_string); - } - - // SLT timestamp - LLSD substitution; - substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected(); - support << "\n" << LLTrans::getString("AboutTime", substitution, default_string); - - return support.str(); + support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string); + if (info.has("COMPILER")) + { + support << "\n" << LLTrans::getString("AboutCompiler", args, default_string); + } + if (info.has("PACKETS_IN")) + { + support << '\n' << LLTrans::getString("AboutTraffic", args, default_string); + } + + // SLT timestamp + LLSD substitution; + substitution["datetime"] = (S32)time(NULL);//(S32)time_corrected(); + support << "\n" << LLTrans::getString("AboutTime", substitution, default_string); + + return support.str(); } void LLAppViewer::cleanupSavedSettings() { - gSavedSettings.setBOOL("MouseSun", FALSE); + gSavedSettings.setBOOL("MouseSun", FALSE); - gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator + gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator - gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); + gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); - gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); + gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates); - if (gDebugView) - { - gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); - } + if (gDebugView) + { + gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible()); + } - // save window position if not maximized - // as we don't track it in callbacks - if(NULL != gViewerWindow) - { - BOOL maximized = gViewerWindow->getWindow()->getMaximized(); - if (!maximized) - { - LLCoordScreen window_pos; + // save window position if not maximized + // as we don't track it in callbacks + if(NULL != gViewerWindow) + { + BOOL maximized = gViewerWindow->getWindow()->getMaximized(); + if (!maximized) + { + LLCoordScreen window_pos; - if (gViewerWindow->getWindow()->getPosition(&window_pos)) - { - gSavedSettings.setS32("WindowX", window_pos.mX); - gSavedSettings.setS32("WindowY", window_pos.mY); - } - } - } + if (gViewerWindow->getWindow()->getPosition(&window_pos)) + { + gSavedSettings.setS32("WindowX", window_pos.mX); + gSavedSettings.setS32("WindowY", window_pos.mY); + } + } + } gSavedSettings.setF32("MapScale", LLWorldMapView::getScaleSetting()); - // Some things are cached in LLAgent. - if (gAgent.isInitialized()) - { - gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); - } + // Some things are cached in LLAgent. + if (gAgent.isInitialized()) + { + gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); + } } void LLAppViewer::removeCacheFiles(const std::string& file_mask) { - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask); + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask); } void LLAppViewer::writeSystemInfo() @@ -3609,96 +3609,96 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["Dynamic"] = LLSD::emptyMap(); #if LL_WINDOWS && !LL_BUGSPLAT - gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); + gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); #else //Not ideal but sufficient for good reporting. gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); //LLError::logFileName(); #endif - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); - gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); + gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); - gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); - gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString(); - gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); - gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz(); - gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); - gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); - gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); + gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString(); + gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); + gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz(); + gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); + gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); + gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); - gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); - gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits()); - gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); + gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); + gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits()); + gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple(); - // The user is not logged on yet, but record the current grid choice login url - // which may have been the intended grid. - gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); + // The user is not logged on yet, but record the current grid choice login url + // which may have been the intended grid. + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); - // *FIX:Mani - move this down in llappviewerwin32 + // *FIX:Mani - move this down in llappviewerwin32 #ifdef LL_WINDOWS - DWORD thread_id = GetCurrentThreadId(); - gDebugInfo["MainloopThreadID"] = (S32)thread_id; + DWORD thread_id = GetCurrentThreadId(); + gDebugInfo["MainloopThreadID"] = (S32)thread_id; #endif #ifndef LL_BUGSPLAT - // "CrashNotHandled" is set here, while things are running well, - // in case of a freeze. If there is a freeze, the crash logger will be launched - // and can read this value from the debug_info.log. - gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); + // "CrashNotHandled" is set here, while things are running well, + // in case of a freeze. If there is a freeze, the crash logger will be launched + // and can read this value from the debug_info.log. + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); #else // LL_BUGSPLAT - // "CrashNotHandled" is obsolete; it used (not very successsfully) + // "CrashNotHandled" is obsolete; it used (not very successsfully) // to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze - gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); + gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); #endif // ! LL_BUGSPLAT - // Insert crash host url (url to post crash log to) if configured. This insures - // that the crash report will go to the proper location in the case of a - // prior freeze. - std::string crashHostUrl = gSavedSettings.get("CrashHostUrl"); - if(crashHostUrl != "") - { - gDebugInfo["CrashHostUrl"] = crashHostUrl; - } - - // Dump some debugging info - LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; - LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; - - // Dump the local time and time zone - time_t now; - time(&now); - char tbuffer[256]; /* Flawfinder: ignore */ - strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now)); - LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL; - - // query some system information - LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL; - LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL; - LL_INFOS("SystemInfo") << "OS: " << LLOSInfo::instance().getOSStringSimple() << LL_ENDL; - LL_INFOS("SystemInfo") << "OS info: " << LLOSInfo::instance() << LL_ENDL; + // Insert crash host url (url to post crash log to) if configured. This insures + // that the crash report will go to the proper location in the case of a + // prior freeze. + std::string crashHostUrl = gSavedSettings.get("CrashHostUrl"); + if(crashHostUrl != "") + { + gDebugInfo["CrashHostUrl"] = crashHostUrl; + } + + // Dump some debugging info + LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; + LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; + + // Dump the local time and time zone + time_t now; + time(&now); + char tbuffer[256]; /* Flawfinder: ignore */ + strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now)); + LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL; + + // query some system information + LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL; + LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL; + LL_INFOS("SystemInfo") << "OS: " << LLOSInfo::instance().getOSStringSimple() << LL_ENDL; + LL_INFOS("SystemInfo") << "OS info: " << LLOSInfo::instance() << LL_ENDL; gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); - gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); - gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); - gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); + gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin()); + gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); if (gViewerWindow) { - std::vector resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); - for (auto res_iter : resolutions) - { - gDebugInfo["DisplayInfo"].append(res_iter); - } + std::vector resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); + for (auto res_iter : resolutions) + { + gDebugInfo["DisplayInfo"].append(res_iter); + } } - writeDebugInfo(); // Save out debug_info.log early, in case of crash. + writeDebugInfo(); // Save out debug_info.log early, in case of crash. } #ifdef LL_WINDOWS @@ -3710,265 +3710,265 @@ void LLAppViewer::writeSystemInfo() // TODO make this a member function. void getFileList() { - std::stringstream filenames; - - typedef std::vector vec; - std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); - vec file_vec = gDirUtilp->getFilesInDir(pathname); - for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) - { - filenames << *iter << " "; - if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) - { - std::string fullname = pathname + *iter; - llifstream fdat( fullname.c_str(), std::ifstream::binary); - if (fdat) - { - char buf[5]; - fdat.read(buf,4); - fdat.close(); - if (!strncmp(buf,"MDMP",4)) - { - gDebugInfo["Dynamic"]["MinidumpPath"] = fullname; - break; - } - } - } - } - filenames << std::endl; - gDebugInfo["Dynamic"]["DumpDirContents"] = filenames.str(); + std::stringstream filenames; + + typedef std::vector vec; + std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); + vec file_vec = gDirUtilp->getFilesInDir(pathname); + for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) + { + filenames << *iter << " "; + if ( ( iter->length() > 30 ) && (iter->rfind(".dmp") == (iter->length()-4) ) ) + { + std::string fullname = pathname + *iter; + llifstream fdat( fullname.c_str(), std::ifstream::binary); + if (fdat) + { + char buf[5]; + fdat.read(buf,4); + fdat.close(); + if (!strncmp(buf,"MDMP",4)) + { + gDebugInfo["Dynamic"]["MinidumpPath"] = fullname; + break; + } + } + } + } + filenames << std::endl; + gDebugInfo["Dynamic"]["DumpDirContents"] = filenames.str(); } #endif // static void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) { - std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); - if ( marker_version.length() > MAX_MARKER_LENGTH ) - { - LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" - << " greater than maximum (" << MAX_MARKER_LENGTH << ")" - << ": marker matching may be incorrect" - << LL_ENDL; - } - - // record the viewer version in the marker file - marker_file.write(marker_version.data(), marker_version.length()); + std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); + if ( marker_version.length() > MAX_MARKER_LENGTH ) + { + LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" + << " greater than maximum (" << MAX_MARKER_LENGTH << ")" + << ": marker matching may be incorrect" + << LL_ENDL; + } + + // record the viewer version in the marker file + marker_file.write(marker_version.data(), marker_version.length()); } bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const { - bool sameVersion = false; - - std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); - char marker_version[MAX_MARKER_LENGTH]; - S32 marker_version_length; - - LLAPRFile marker_file; - marker_file.open(marker_name, LL_APR_RB); - if (marker_file.getFileHandle()) - { - marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); - std::string marker_string(marker_version, marker_version_length); - if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) - { - sameVersion = true; - } - LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " - << "\n mine '" << my_version << "'" - << "\n marker '" << marker_string << "'" - << "\n " << ( sameVersion ? "same" : "different" ) << " version" - << LL_ENDL; - marker_file.close(); - } - return sameVersion; + bool sameVersion = false; + + std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); + char marker_version[MAX_MARKER_LENGTH]; + S32 marker_version_length; + + LLAPRFile marker_file; + marker_file.open(marker_name, LL_APR_RB); + if (marker_file.getFileHandle()) + { + marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); + std::string marker_string(marker_version, marker_version_length); + if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) + { + sameVersion = true; + } + LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " + << "\n mine '" << my_version << "'" + << "\n marker '" << marker_string << "'" + << "\n " << ( sameVersion ? "same" : "different" ) << " version" + << LL_ENDL; + marker_file.close(); + } + return sameVersion; } void LLAppViewer::processMarkerFiles() { - //We've got 4 things to test for here - // - Other Process Running (SecondLife.exec_marker present, locked) - // - Freeze (SecondLife.exec_marker present, not locked) - // - LLError Crash (SecondLife.llerror_marker present) - // - Other Crash (SecondLife.error_marker present) - // These checks should also remove these files for the last 2 cases if they currently exist - - std::ostringstream marker_log_stream; - bool marker_is_same_version = true; - // first, look for the marker created at startup and deleted on a clean exit - mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) - { - // File exists... - // first, read it to see if it was created by the same version (we need this later) - marker_is_same_version = markerIsSameVersion(mMarkerFileName); - - // now test to see if this file is locked by a running process (try to open for write) - marker_log_stream << "Checking exec marker file for lock..."; - mMarkerFile.open(mMarkerFileName, LL_APR_WB); - apr_file_t* fMarker = mMarkerFile.getFileHandle() ; - if (!fMarker) - { - marker_log_stream << "Exec marker file open failed - assume it is locked."; - mSecondInstance = true; // lock means that instance is running. - } - else - { - // We were able to open it, now try to lock it ourselves... - if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) - { - marker_log_stream << "Locking exec marker failed."; - mSecondInstance = true; // lost a race? be conservative - } - else - { - // No other instances; we've locked this file now, so record our version; delete on quit. - recordMarkerVersion(mMarkerFile); - marker_log_stream << "Exec marker file existed but was not locked; rewritten."; - } - } - initLoggingAndGetLastDuration(); - - std::string marker_log_msg(marker_log_stream.str()); - LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; - - if (mSecondInstance) - { - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; - } - else if (marker_is_same_version) - { - // the file existed, is ours, and matched our version, so we can report on what it says - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; - gLastExecEvent = LAST_EXEC_OTHER_CRASH; - } - else - { - LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; - } - } - else // marker did not exist... last exec (if any) did not freeze - { - initLoggingAndGetLastDuration(); - // Create the marker file for this execution & lock it; it will be deleted on a clean exit - apr_status_t s; - s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); - - if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) - { - LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; - if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) - { - recordMarkerVersion(mMarkerFile); - LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; - } - else - { - LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; - } - } - else - { - LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; - } - } - - // now check for cases in which the exec marker may have been cleaned up by crash handlers - - // check for any last exec event report based on whether or not it happened during logout - // (the logout marker is created when logout begins) - std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(logout_marker_file)) - { - gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; - LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; - } - else - { - LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(logout_marker_file); - } - // further refine based on whether or not a marker created during an llerr crash is found - std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(llerror_marker_file)) - { - if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_LLERROR_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(llerror_marker_file); - } - // and last refine based on whether or not a marker created during a non-llerr crash is found - std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(error_marker_file)) - { - if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_OTHER_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(error_marker_file); - } + //We've got 4 things to test for here + // - Other Process Running (SecondLife.exec_marker present, locked) + // - Freeze (SecondLife.exec_marker present, not locked) + // - LLError Crash (SecondLife.llerror_marker present) + // - Other Crash (SecondLife.error_marker present) + // These checks should also remove these files for the last 2 cases if they currently exist + + std::ostringstream marker_log_stream; + bool marker_is_same_version = true; + // first, look for the marker created at startup and deleted on a clean exit + mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); + if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) + { + // File exists... + // first, read it to see if it was created by the same version (we need this later) + marker_is_same_version = markerIsSameVersion(mMarkerFileName); + + // now test to see if this file is locked by a running process (try to open for write) + marker_log_stream << "Checking exec marker file for lock..."; + mMarkerFile.open(mMarkerFileName, LL_APR_WB); + apr_file_t* fMarker = mMarkerFile.getFileHandle() ; + if (!fMarker) + { + marker_log_stream << "Exec marker file open failed - assume it is locked."; + mSecondInstance = true; // lock means that instance is running. + } + else + { + // We were able to open it, now try to lock it ourselves... + if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) + { + marker_log_stream << "Locking exec marker failed."; + mSecondInstance = true; // lost a race? be conservative + } + else + { + // No other instances; we've locked this file now, so record our version; delete on quit. + recordMarkerVersion(mMarkerFile); + marker_log_stream << "Exec marker file existed but was not locked; rewritten."; + } + } + initLoggingAndGetLastDuration(); + + std::string marker_log_msg(marker_log_stream.str()); + LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; + + if (mSecondInstance) + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; + } + else if (marker_is_same_version) + { + // the file existed, is ours, and matched our version, so we can report on what it says + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + } + else + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; + } + } + else // marker did not exist... last exec (if any) did not freeze + { + initLoggingAndGetLastDuration(); + // Create the marker file for this execution & lock it; it will be deleted on a clean exit + apr_status_t s; + s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); + + if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) + { + LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; + if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) + { + recordMarkerVersion(mMarkerFile); + LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; + } + } + else + { + LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; + } + } + + // now check for cases in which the exec marker may have been cleaned up by crash handlers + + // check for any last exec event report based on whether or not it happened during logout + // (the logout marker is created when logout begins) + std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); + if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(logout_marker_file)) + { + gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; + } + else + { + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(logout_marker_file); + } + // further refine based on whether or not a marker created during an llerr crash is found + std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); + if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(llerror_marker_file)) + { + if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(llerror_marker_file); + } + // and last refine based on whether or not a marker created during a non-llerr crash is found + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + { + if (markerIsSameVersion(error_marker_file)) + { + if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; + } + LLAPRFile::remove(error_marker_file); + } } void LLAppViewer::removeMarkerFiles() { - if (!mSecondInstance) - { - if (mMarkerFile.getFileHandle()) - { - mMarkerFile.close() ; - LLAPRFile::remove( mMarkerFileName ); - LL_DEBUGS("MarkerFile") << "removed exec marker '"<updateAvatarRezMetrics(true); // force a last packet to be sent. - } - - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - effectp->markDead() ;//remove it. - - // Attempt to close all floaters that might be - // editing things. - if (gFloaterView) - { - // application is quitting - gFloaterView->closeAllChildren(true); - } - - // Send preferences once, when exiting - bool include_preferences = true; - send_viewer_stats(include_preferences); - - gLogoutTimer.reset(); - mQuitRequested = true; + LL_INFOS() << "requestQuit" << LL_ENDL; + + LLViewerRegion* region = gAgent.getRegion(); + + if( (LLStartUp::getStartupState() < STATE_STARTED) || !region ) + { + // If we have a region, make some attempt to send a logout request first. + // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes. + if(region) + { + sendLogoutRequest(); + } + + // Quit immediately + forceQuit(); + return; + } + + // Try to send metrics back to the grid + metricsSend(!gDisconnected); + + // Try to send last batch of avatar rez metrics. + if (!gDisconnected && isAgentAvatarValid()) + { + gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent. + } + + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + effectp->markDead() ;//remove it. + + // Attempt to close all floaters that might be + // editing things. + if (gFloaterView) + { + // application is quitting + gFloaterView->closeAllChildren(true); + } + + // Send preferences once, when exiting + bool include_preferences = true; + send_viewer_stats(include_preferences); + + gLogoutTimer.reset(); + mQuitRequested = true; } static bool finish_quit(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLAppViewer::instance()->requestQuit(); - } - return false; + if (option == 0) + { + LLAppViewer::instance()->requestQuit(); + } + return false; } static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit); void LLAppViewer::userQuit() { - LL_INFOS() << "User requested quit" << LL_ENDL; - if (gDisconnected - || !gViewerWindow - || !gViewerWindow->getProgressView() - || gViewerWindow->getProgressView()->getVisible()) - { - requestQuit(); - } - else - { - LLNotificationsUtil::add("ConfirmQuit"); - } + LL_INFOS() << "User requested quit" << LL_ENDL; + if (gDisconnected + || !gViewerWindow + || !gViewerWindow->getProgressView() + || gViewerWindow->getProgressView()->getVisible()) + { + requestQuit(); + } + else + { + LLNotificationsUtil::add("ConfirmQuit"); + } } static bool finish_early_exit(const LLSD& notification, const LLSD& response) { - LLAppViewer::instance()->forceQuit(); - return false; + LLAppViewer::instance()->forceQuit(); + return false; } void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) { - LL_WARNS() << "app_early_exit: " << name << LL_ENDL; - gDoDisconnect = TRUE; - LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); + LL_WARNS() << "app_early_exit: " << name << LL_ENDL; + gDoDisconnect = TRUE; + LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); } // case where we need the viewer to exit without any need for notifications void LLAppViewer::earlyExitNoNotify() { - LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL; - gDoDisconnect = TRUE; - finish_early_exit( LLSD(), LLSD() ); + LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL; + gDoDisconnect = TRUE; + finish_early_exit( LLSD(), LLSD() ); } void LLAppViewer::abortQuit() { LL_INFOS() << "abortQuit()" << LL_ENDL; - mQuitRequested = false; + mQuitRequested = false; } void LLAppViewer::migrateCacheDirectory() { #if LL_WINDOWS || LL_DARWIN - // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from - // /library/application support/SecondLife/cache This should clear/delete the old dir. - - // As of 1.23 the Windows cache moved from - // C:\Documents and Settings\James\Application Support\SecondLife\cache - // to - // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife - // - // The Windows Vista equivalent is from - // C:\Users\James\AppData\Roaming\SecondLife\cache - // to - // C:\Users\James\AppData\Local\SecondLife - // - // Note the absence of \cache on the second path. James. - - // Only do this once per fresh install of this version. - if (gSavedSettings.getBOOL("MigrateCacheDirectory")) - { - gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); - - std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); - std::string new_cache_dir = gDirUtilp->getCacheDir(true); - - if (gDirUtilp->fileExists(old_cache_dir)) - { - LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; - - // Migrate inventory cache to avoid pain to inventory database after mass update - S32 file_count = 0; - std::string file_name; - std::string mask = "*.*"; - - LLDirIterator iter(old_cache_dir, mask); - while (iter.next(file_name)) - { - if (file_name == "." || file_name == "..") continue; - std::string source_path = gDirUtilp->add(old_cache_dir, file_name); - std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); - if (!LLFile::rename(source_path, dest_path)) - { - file_count++; - } - } - LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; - - // Nuke the old cache - gDirUtilp->setCacheDir(old_cache_dir); - purgeCache(); - gDirUtilp->setCacheDir(new_cache_dir); + // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from + // /library/application support/SecondLife/cache This should clear/delete the old dir. + + // As of 1.23 the Windows cache moved from + // C:\Documents and Settings\James\Application Support\SecondLife\cache + // to + // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife + // + // The Windows Vista equivalent is from + // C:\Users\James\AppData\Roaming\SecondLife\cache + // to + // C:\Users\James\AppData\Local\SecondLife + // + // Note the absence of \cache on the second path. James. + + // Only do this once per fresh install of this version. + if (gSavedSettings.getBOOL("MigrateCacheDirectory")) + { + gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); + + std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); + std::string new_cache_dir = gDirUtilp->getCacheDir(true); + + if (gDirUtilp->fileExists(old_cache_dir)) + { + LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; + + // Migrate inventory cache to avoid pain to inventory database after mass update + S32 file_count = 0; + std::string file_name; + std::string mask = "*.*"; + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) + { + if (file_name == "." || file_name == "..") continue; + std::string source_path = gDirUtilp->add(old_cache_dir, file_name); + std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); + if (!LLFile::rename(source_path, dest_path)) + { + file_count++; + } + } + LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; + + // Nuke the old cache + gDirUtilp->setCacheDir(old_cache_dir); + purgeCache(); + gDirUtilp->setCacheDir(new_cache_dir); #if LL_DARWIN - // Clean up Mac files not deleted by removing *.* - std::string ds_store = old_cache_dir + "/.DS_Store"; - if (gDirUtilp->fileExists(ds_store)) - { - LLFile::remove(ds_store); - } + // Clean up Mac files not deleted by removing *.* + std::string ds_store = old_cache_dir + "/.DS_Store"; + if (gDirUtilp->fileExists(ds_store)) + { + LLFile::remove(ds_store); + } #endif - if (LLFile::rmdir(old_cache_dir) != 0) - { - LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; - } - } - } + if (LLFile::rmdir(old_cache_dir) != 0) + { + LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; + } + } + } #endif // LL_WINDOWS || LL_DARWIN } //static U32 LLAppViewer::getTextureCacheVersion() { - // Viewer texture cache version, change if the texture cache format changes. - // 2021-03-10 Bumping up by one to help obviate texture cache issues with - // Simple Cache Viewer - see SL-14985 for more information - //const U32 TEXTURE_CACHE_VERSION = 8; - const U32 TEXTURE_CACHE_VERSION = 9; + // Viewer texture cache version, change if the texture cache format changes. + // 2021-03-10 Bumping up by one to help obviate texture cache issues with + // Simple Cache Viewer - see SL-14985 for more information + //const U32 TEXTURE_CACHE_VERSION = 8; + const U32 TEXTURE_CACHE_VERSION = 9; - return TEXTURE_CACHE_VERSION ; + return TEXTURE_CACHE_VERSION ; } //static @@ -4211,92 +4211,92 @@ U32 LLAppViewer::getDiskCacheVersion() //static U32 LLAppViewer::getObjectCacheVersion() { - // Viewer object cache version, change if object update - // format changes. JC - const U32 INDRA_OBJECT_CACHE_VERSION = 17; + // Viewer object cache version, change if object update + // format changes. JC + const U32 INDRA_OBJECT_CACHE_VERSION = 17; - return INDRA_OBJECT_CACHE_VERSION; + return INDRA_OBJECT_CACHE_VERSION; } bool LLAppViewer::initCache() { - mPurgeCache = false; - BOOL read_only = mSecondInstance ? TRUE : FALSE; - LLAppViewer::getTextureCache()->setReadOnly(read_only) ; - LLVOCache::initParamSingleton(read_only); + mPurgeCache = false; + BOOL read_only = mSecondInstance ? TRUE : FALSE; + LLAppViewer::getTextureCache()->setReadOnly(read_only) ; + LLVOCache::initParamSingleton(read_only); - // initialize the new disk cache using saved settings - const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); + // initialize the new disk cache using saved settings + const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); - const U32 MB = 1024 * 1024; + const U32 MB = 1024 * 1024; const uintmax_t MIN_CACHE_SIZE = 256 * MB; - const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; + const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB; const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); const F64 texture_cache_percent = 100.0 - disk_cache_percent; - // note that the maximum size of this cache is defined as a percentage of the - // total cache size - the 'CacheSize' pref - for all caches. + // note that the maximum size of this cache is defined as a percentage of the + // total cache size - the 'CacheSize' pref - for all caches. const uintmax_t disk_cache_size = uintmax_t(cache_total_size * disk_cache_percent / 100); - const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); + const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); - bool texture_cache_mismatch = false; + bool texture_cache_mismatch = false; bool remove_vfs_files = false; - if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) - { - texture_cache_mismatch = true; - if(!read_only) - { - gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); + if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) + { + texture_cache_mismatch = true; + if(!read_only) + { + gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); //texture cache version was bumped up in Simple Cache Viewer, and at this point old vfs files are not needed - remove_vfs_files = true; - } - } - - if(!read_only) - { - // Purge cache if user requested it - if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || - gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) - { - LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); - mPurgeCache = true; - // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad - texture_cache_mismatch = true; - } - - // We have moved the location of the cache directory over time. - migrateCacheDirectory(); - - // Setup and verify the cache location - std::string cache_location = gSavedSettings.getString("CacheLocation"); - std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); - if (new_cache_location != cache_location) - { - LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; - gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); - purgeCache(); // purge old cache - gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); - gSavedSettings.setString("CacheLocation", new_cache_location); - gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); - } - } - - if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) - { - LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; - gSavedSettings.setString("CacheLocation", ""); - gSavedSettings.setString("CacheLocationTopFolder", ""); - } - - const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); - LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); - - if (!read_only) - { + remove_vfs_files = true; + } + } + + if(!read_only) + { + // Purge cache if user requested it + if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || + gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) + { + LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); + mPurgeCache = true; + // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad + texture_cache_mismatch = true; + } + + // We have moved the location of the cache directory over time. + migrateCacheDirectory(); + + // Setup and verify the cache location + std::string cache_location = gSavedSettings.getString("CacheLocation"); + std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); + if (new_cache_location != cache_location) + { + LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; + gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); + purgeCache(); // purge old cache + gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); + gSavedSettings.setString("CacheLocation", new_cache_location); + gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); + } + } + + if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) + { + LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; + gSavedSettings.setString("CacheLocation", ""); + gSavedSettings.setString("CacheLocationTopFolder", ""); + } + + const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); + LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); + + if (!read_only) + { if (gSavedSettings.getS32("DiskCacheVersion") != LLAppViewer::getDiskCacheVersion()) { LLDiskCache::getInstance()->clearCache(); @@ -4308,166 +4308,166 @@ bool LLAppViewer::initCache() { LLDiskCache::getInstance()->removeOldVFSFiles(); } - + if (mPurgeCache) - { - LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); - purgeCache(); - - // clear the new C++ file system based cache - LLDiskCache::getInstance()->clearCache(); - } - else - { - // purge excessive files from the new file system based cache - LLDiskCache::getInstance()->purge(); - } - } - LLAppViewer::getPurgeDiskCacheThread()->start(); - - LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); - - // Init the texture cache + { + LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); + purgeCache(); + + // clear the new C++ file system based cache + LLDiskCache::getInstance()->clearCache(); + } + else + { + // purge excessive files from the new file system based cache + LLDiskCache::getInstance()->purge(); + } + } + LLAppViewer::getPurgeDiskCacheThread()->start(); + + LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); + + // Init the texture cache // Allocate the remaining percent which is not allocated to the disk cache const S64 texture_cache_size = S64(cache_total_size * texture_cache_percent / 100); LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); - LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); + LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); return true; } void LLAppViewer::addOnIdleCallback(const boost::function& cb) { - gMainloopWork.post(cb); + gMainloopWork.post(cb); } void LLAppViewer::loadKeyBindings() { - std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); - if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) - { - // Failed to load custom bindings, try default ones - key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); - if (!gViewerInput.loadBindingsXML(key_bindings_file)) - { + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) + { + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; - } - } + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; + } + } LLUrlRegistry::instance().setKeybindingHandler(&gViewerInput); } void LLAppViewer::purgeCache() { - LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; - LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); - LLViewerShaderMgr::instance()->clearShaderCache(); - std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); - if (LLFile::isdir(browser_cache)) - { - // cef does not support clear_cache and clear_cookies, so clear what we can manually. - gDirUtilp->deleteDirAndContents(browser_cache); - } - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*"); + LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; + LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); + LLViewerShaderMgr::instance()->clearShaderCache(); + std::string browser_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache"); + if (LLFile::isdir(browser_cache)) + { + // cef does not support clear_cache and clear_cookies, so clear what we can manually. + gDirUtilp->deleteDirAndContents(browser_cache); + } + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*"); } //purge cache immediately, do not wait until the next login. void LLAppViewer::purgeCacheImmediate() { - LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; - LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); - LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); + LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL; + LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE, false); + LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true); } std::string LLAppViewer::getSecondLifeTitle() const { - return LLTrans::getString("APP_NAME"); + return LLTrans::getString("APP_NAME"); } std::string LLAppViewer::getWindowTitle() const { - return gWindowTitle; + return gWindowTitle; } // Callback from a dialog indicating user was logged out. bool finish_disconnect(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (1 == option) - { + if (1 == option) + { LLAppViewer::instance()->forceQuit(); - } - return false; + } + return false; } // Callback from an early disconnect dialog, force an exit bool finish_forced_disconnect(const LLSD& notification, const LLSD& response) { - LLAppViewer::instance()->forceQuit(); - return false; + LLAppViewer::instance()->forceQuit(); + return false; } void LLAppViewer::forceDisconnect(const std::string& mesg) { - if (gDoDisconnect) - { - // Already popped up one of these dialogs, don't - // do this again. - return; - } - - // *TODO: Translate the message if possible - std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; - if ( big_reason.size() == 0 ) - { - big_reason = mesg; - } - - LLSD args; - gDoDisconnect = TRUE; - - if (LLStartUp::getStartupState() < STATE_STARTED) - { - // Tell users what happened - args["ERROR_MESSAGE"] = big_reason; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); - } - else - { - args["MESSAGE"] = big_reason; - LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); - } + if (gDoDisconnect) + { + // Already popped up one of these dialogs, don't + // do this again. + return; + } + + // *TODO: Translate the message if possible + std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; + if ( big_reason.size() == 0 ) + { + big_reason = mesg; + } + + LLSD args; + gDoDisconnect = TRUE; + + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // Tell users what happened + args["ERROR_MESSAGE"] = big_reason; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); + } + else + { + args["MESSAGE"] = big_reason; + LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); + } } void LLAppViewer::badNetworkHandler() { - // Dump the packet - gMessageSystem->dumpPacketToLog(); - - // Flush all of our caches on exit in the case of disconnect due to - // invalid packets. - - mPurgeCacheOnExit = TRUE; - - std::ostringstream message; - message << - "The viewer has detected mangled network data indicative\n" - "of a bad upstream network connection or an incomplete\n" - "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" - " \n" - "Try uninstalling and reinstalling to see if this resolves \n" - "the issue. \n" - " \n" - "If the problem continues, see the Tech Support FAQ at: \n" - "www.secondlife.com/support"; - forceDisconnect(message.str()); - - LLApp::instance()->writeMiniDump(); + // Dump the packet + gMessageSystem->dumpPacketToLog(); + + // Flush all of our caches on exit in the case of disconnect due to + // invalid packets. + + mPurgeCacheOnExit = TRUE; + + std::ostringstream message; + message << + "The viewer has detected mangled network data indicative\n" + "of a bad upstream network connection or an incomplete\n" + "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" + " \n" + "Try uninstalling and reinstalling to see if this resolves \n" + "the issue. \n" + " \n" + "If the problem continues, see the Tech Support FAQ at: \n" + "www.secondlife.com/support"; + forceDisconnect(message.str()); + + LLApp::instance()->writeMiniDump(); } // This routine may get called more than once during the shutdown process. @@ -4475,93 +4475,93 @@ void LLAppViewer::badNetworkHandler() // is destroyed. void LLAppViewer::saveFinalSnapshot() { - if (!mSavedFinalSnapshot) - { - gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); - gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); - gViewerWindow->setCursor(UI_CURSOR_WAIT); - gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch - gSavedSettings.setBOOL("ShowParcelOwners", FALSE); - idle(); - - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenLastFilename(); - // use full pixel dimensions of viewer window (not post-scale dimensions) - gViewerWindow->saveSnapshot(snap_filename, - gViewerWindow->getWindowWidthRaw(), - gViewerWindow->getWindowHeightRaw(), - FALSE, - gSavedSettings.getBOOL("RenderHUDInSnapshot"), - TRUE, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - mSavedFinalSnapshot = TRUE; - - if (gAgent.isInHomeRegion()) - { - LLVector3d home; - if (gAgent.getHomePosGlobal(&home) && dist_vec(home, gAgent.getPositionGlobal()) < 10) - { - // We are at home position or close to it, see if we need to create home screenshot - // Notes: - // 1. It might be beneficial to also replace home if file is too old - // 2. This is far from best way/place to update screenshot since location might be not fully loaded, - // but we don't have many options - std::string snap_home = gDirUtilp->getLindenUserDir(); - snap_home += gDirUtilp->getDirDelimiter(); - snap_home += LLStartUp::getScreenHomeFilename(); - if (!gDirUtilp->fileExists(snap_home)) - { - // We are at home position yet no home image exist, fix it - LLFile::copy(snap_filename, snap_home); - } - } - } - } + if (!mSavedFinalSnapshot) + { + gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal()); + gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal()); + gViewerWindow->setCursor(UI_CURSOR_WAIT); + gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch + gSavedSettings.setBOOL("ShowParcelOwners", FALSE); + idle(); + + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenLastFilename(); + // use full pixel dimensions of viewer window (not post-scale dimensions) + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + TRUE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + mSavedFinalSnapshot = TRUE; + + if (gAgent.isInHomeRegion()) + { + LLVector3d home; + if (gAgent.getHomePosGlobal(&home) && dist_vec(home, gAgent.getPositionGlobal()) < 10) + { + // We are at home position or close to it, see if we need to create home screenshot + // Notes: + // 1. It might be beneficial to also replace home if file is too old + // 2. This is far from best way/place to update screenshot since location might be not fully loaded, + // but we don't have many options + std::string snap_home = gDirUtilp->getLindenUserDir(); + snap_home += gDirUtilp->getDirDelimiter(); + snap_home += LLStartUp::getScreenHomeFilename(); + if (!gDirUtilp->fileExists(snap_home)) + { + // We are at home position yet no home image exist, fix it + LLFile::copy(snap_filename, snap_home); + } + } + } + } } void LLAppViewer::loadNameCache() { - // display names cache - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - LL_INFOS("AvNameCache") << filename << LL_ENDL; - llifstream name_cache_stream(filename.c_str()); - if(name_cache_stream.is_open()) - { - if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) + // display names cache + std::string filename = + gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + LL_INFOS("AvNameCache") << filename << LL_ENDL; + llifstream name_cache_stream(filename.c_str()); + if(name_cache_stream.is_open()) + { + if ( ! LLAvatarNameCache::getInstance()->importFile(name_cache_stream)) { LL_WARNS("AppInit") << "removing invalid '" << filename << "'" << LL_ENDL; name_cache_stream.close(); LLFile::remove(filename); } - } + } - if (!gCacheName) return; + if (!gCacheName) return; - std::string name_cache; - name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); - llifstream cache_file(name_cache.c_str()); - if(cache_file.is_open()) - { - if(gCacheName->importFile(cache_file)) return; - } + std::string name_cache; + name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); + llifstream cache_file(name_cache.c_str()); + if(cache_file.is_open()) + { + if(gCacheName->importFile(cache_file)) return; + } } void LLAppViewer::saveNameCache() { - // display names cache - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - llofstream name_cache_stream(filename.c_str()); - if(name_cache_stream.is_open()) - { - LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); + // display names cache + std::string filename = + gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + llofstream name_cache_stream(filename.c_str()); + if(name_cache_stream.is_open()) + { + LLAvatarNameCache::getInstance()->exportFile(name_cache_stream); } // real names cache - if (gCacheName) + if (gCacheName) { std::string name_cache; name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); @@ -4570,24 +4570,24 @@ void LLAppViewer::saveNameCache() { gCacheName->exportFile(cache_file); } - } + } } -/*! @brief This class is an LLFrameTimer that can be created with - an elapsed time that starts counting up from the given value - rather than 0.0. +/*! @brief This class is an LLFrameTimer that can be created with + an elapsed time that starts counting up from the given value + rather than 0.0. - Otherwise it behaves the same way as LLFrameTimer. + Otherwise it behaves the same way as LLFrameTimer. */ class LLFrameStatsTimer : public LLFrameTimer { public: - LLFrameStatsTimer(F64 elapsed_already = 0.0) - : LLFrameTimer() - { - mStartTime -= elapsed_already; - } + LLFrameStatsTimer(F64 elapsed_already = 0.0) + : LLFrameTimer() + { + mStartTime -= elapsed_already; + } }; static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio"); @@ -4612,118 +4612,118 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); /////////////////////////////////////////////////////// void LLAppViewer::idle() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - pingMainloopTimeout("Main:Idle"); - - // Update frame timers - static LLTimer idle_timer; - - LLFrameTimer::updateFrameTime(); - LLFrameTimer::updateFrameCount(); - LLPerfStats::updateClass(); - - // LLApp::stepFrame() performs the above three calls plus mRunner.run(). - // Not sure why we don't call stepFrame() here, except that LLRunner seems - // completely redundant with LLEventTimer. - LLNotificationsUI::LLToast::updateClass(); - LLSmoothInterpolation::updateInterpolants(); - LLMortician::updateClass(); - LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() - LLDirPickerThread::clearDead(); - F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); - - LLGLTFMaterialList::flushUpdates(); - - // Service the WorkQueue we use for replies from worker threads. - // Use function statics for the timeslice setting so we only have to fetch - // and convert MainWorkTime once. - static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); - static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); - // MainWorkTime is specified in fractional milliseconds, but std::chrono - // uses integer representations. What if we want less than a microsecond? - // Use nanoseconds. We're very sure we will never need to specify a - // MainWorkTime that would be larger than we could express in - // std::chrono::nanoseconds. - static std::chrono::nanoseconds MainWorkTimeNanoSec{ - std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; - gMainloopWork.runFor(MainWorkTimeNanoSec); - - // Cap out-of-control frame times - // Too low because in menus, swapping, debugger, etc. - // Too high because idle called with no objects in view, etc. - const F32 MIN_FRAME_RATE = 1.f; - const F32 MAX_FRAME_RATE = 200.f; - - F32 frame_rate_clamped = 1.f / dt_raw; - frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); - gFrameDTClamped = 1.f / frame_rate_clamped; - - // Global frame timer - // Smoothly weight toward current frame - gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; - - F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); - if (qas > 0.f) - { - if (gRenderStartTime.getElapsedTimeF32() > qas) - { - LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; - LLAppViewer::instance()->forceQuit(); - } - } - - // Must wait until both have avatar object and mute list, so poll - // here. - LLIMProcessing::requestOfflineMessages(); - - /////////////////////////////////// - // - // Special case idle if still starting up - // - if (LLStartUp::getStartupState() < STATE_STARTED) - { - // Skip rest if idle startup returns false (essentially, no world yet) - gGLActive = TRUE; - if (!idle_startup()) - { - gGLActive = FALSE; - return; - } - gGLActive = FALSE; - } - - - F32 yaw = 0.f; // radians - - if (!gDisconnected) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); - // Update spaceserver timeinfo - LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); - - - ////////////////////////////////////// - // - // Update simulator agent state - // - - if (gSavedSettings.getBOOL("RotateRight")) - { - gAgent.moveYaw(-1.f); - } - - { + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; + pingMainloopTimeout("Main:Idle"); + + // Update frame timers + static LLTimer idle_timer; + + LLFrameTimer::updateFrameTime(); + LLFrameTimer::updateFrameCount(); + LLPerfStats::updateClass(); + + // LLApp::stepFrame() performs the above three calls plus mRunner.run(). + // Not sure why we don't call stepFrame() here, except that LLRunner seems + // completely redundant with LLEventTimer. + LLNotificationsUI::LLToast::updateClass(); + LLSmoothInterpolation::updateInterpolants(); + LLMortician::updateClass(); + LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() + LLDirPickerThread::clearDead(); + F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); + + LLGLTFMaterialList::flushUpdates(); + + // Service the WorkQueue we use for replies from worker threads. + // Use function statics for the timeslice setting so we only have to fetch + // and convert MainWorkTime once. + static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); + static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); + // MainWorkTime is specified in fractional milliseconds, but std::chrono + // uses integer representations. What if we want less than a microsecond? + // Use nanoseconds. We're very sure we will never need to specify a + // MainWorkTime that would be larger than we could express in + // std::chrono::nanoseconds. + static std::chrono::nanoseconds MainWorkTimeNanoSec{ + std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; + gMainloopWork.runFor(MainWorkTimeNanoSec); + + // Cap out-of-control frame times + // Too low because in menus, swapping, debugger, etc. + // Too high because idle called with no objects in view, etc. + const F32 MIN_FRAME_RATE = 1.f; + const F32 MAX_FRAME_RATE = 200.f; + + F32 frame_rate_clamped = 1.f / dt_raw; + frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); + gFrameDTClamped = 1.f / frame_rate_clamped; + + // Global frame timer + // Smoothly weight toward current frame + gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; + + F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); + if (qas > 0.f) + { + if (gRenderStartTime.getElapsedTimeF32() > qas) + { + LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; + LLAppViewer::instance()->forceQuit(); + } + } + + // Must wait until both have avatar object and mute list, so poll + // here. + LLIMProcessing::requestOfflineMessages(); + + /////////////////////////////////// + // + // Special case idle if still starting up + // + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // Skip rest if idle startup returns false (essentially, no world yet) + gGLActive = TRUE; + if (!idle_startup()) + { + gGLActive = FALSE; + return; + } + gGLActive = FALSE; + } + + + F32 yaw = 0.f; // radians + + if (!gDisconnected) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); + // Update spaceserver timeinfo + LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); + + + ////////////////////////////////////// + // + // Update simulator agent state + // + + if (gSavedSettings.getBOOL("RotateRight")) + { + gAgent.moveYaw(-1.f); + } + + { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("Autopilot"); - // Handle automatic walking towards points - gAgentPilot.updateTarget(); - gAgent.autoPilot(&yaw); - } + // Handle automatic walking towards points + gAgentPilot.updateTarget(); + gAgent.autoPilot(&yaw); + } - static LLFrameTimer agent_update_timer; + static LLFrameTimer agent_update_timer; - // When appropriate, update agent location to the simulator. - F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); - F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; + // When appropriate, update agent location to the simulator. + F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); + F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; bool timed_out = agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND); BOOL force_send = // if there is something to send @@ -4734,111 +4734,111 @@ void LLAppViewer::idle() || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND)); // timing out doesn't warranty that an update will be sent, // just that it will be checked. - if (force_send || timed_out) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // Send avatar and camera info - mLastAgentControlFlags = gAgent.getControlFlags(); - mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; - send_agent_update(force_send); - agent_update_timer.reset(); - } - } - - ////////////////////////////////////// - // - // Manage statistics - // - // - { - // Initialize the viewer_stats_timer with an already elapsed time - // of SEND_STATS_PERIOD so that the initial stats report will - // be sent immediately. - static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); - - // Update session stats every large chunk of time - // *FIX: (?) SAMANTHA - if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) - { - LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; - bool include_preferences = false; - send_viewer_stats(include_preferences); - viewer_stats_timer.reset(); - } - - // Print the object debugging stats - static LLFrameTimer object_debug_timer; - if (object_debug_timer.getElapsedTimeF32() > 5.f) - { - object_debug_timer.reset(); - if (gObjectList.mNumDeadObjectUpdates) - { - LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; - gObjectList.mNumDeadObjectUpdates = 0; - } - if (gObjectList.mNumUnknownUpdates) - { - LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; - gObjectList.mNumUnknownUpdates = 0; - } - - } - } - - if (!gDisconnected) - { + if (force_send || timed_out) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + // Send avatar and camera info + mLastAgentControlFlags = gAgent.getControlFlags(); + mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; + send_agent_update(force_send); + agent_update_timer.reset(); + } + } + + ////////////////////////////////////// + // + // Manage statistics + // + // + { + // Initialize the viewer_stats_timer with an already elapsed time + // of SEND_STATS_PERIOD so that the initial stats report will + // be sent immediately. + static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); + + // Update session stats every large chunk of time + // *FIX: (?) SAMANTHA + if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) + { + LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; + bool include_preferences = false; + send_viewer_stats(include_preferences); + viewer_stats_timer.reset(); + } + + // Print the object debugging stats + static LLFrameTimer object_debug_timer; + if (object_debug_timer.getElapsedTimeF32() > 5.f) + { + object_debug_timer.reset(); + if (gObjectList.mNumDeadObjectUpdates) + { + LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; + gObjectList.mNumDeadObjectUpdates = 0; + } + if (gObjectList.mNumUnknownUpdates) + { + LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; + gObjectList.mNumUnknownUpdates = 0; + } + + } + } + + if (!gDisconnected) + { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Network"); - //////////////////////////////////////////////// - // - // Network processing - // - // NOTE: Starting at this point, we may still have pointers to "dead" objects - // floating throughout the various object lists. - // - idleNameCache(); - idleNetwork(); + //////////////////////////////////////////////// + // + // Network processing + // + // NOTE: Starting at this point, we may still have pointers to "dead" objects + // floating throughout the various object lists. + // + idleNameCache(); + idleNetwork(); - // Check for away from keyboard, kick idle agents. - idle_afk_check(); + // Check for away from keyboard, kick idle agents. + idle_afk_check(); - // Update statistics for this frame - update_statistics(); - } + // Update statistics for this frame + update_statistics(); + } - //////////////////////////////////////// - // - // Handle the regular UI idle callbacks as well as - // hover callbacks - // + //////////////////////////////////////// + // + // Handle the regular UI idle callbacks as well as + // hover callbacks + // #ifdef LL_DARWIN - if (!mQuitRequested) //MAINT-4243 + if (!mQuitRequested) //MAINT-4243 #endif - { -// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); + { +// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); - // Do event notifications if necessary. Yes, we may want to move this elsewhere. - gEventNotifier.update(); + // Do event notifications if necessary. Yes, we may want to move this elsewhere. + gEventNotifier.update(); - gIdleCallbacks.callFunctions(); - gInventory.idleNotifyObservers(); - LLAvatarTracker::instance().idleNotifyObservers(); - } + gIdleCallbacks.callFunctions(); + gInventory.idleNotifyObservers(); + LLAvatarTracker::instance().idleNotifyObservers(); + } - // Metrics logging (LLViewerAssetStats, etc.) - { - static LLTimer report_interval; + // Metrics logging (LLViewerAssetStats, etc.) + { + static LLTimer report_interval; - // *TODO: Add configuration controls for this - F32 seconds = report_interval.getElapsedTimeF32(); - if (seconds >= app_metrics_interval) - { - metricsSend(! gDisconnected); - report_interval.reset(); - } - } + // *TODO: Add configuration controls for this + F32 seconds = report_interval.getElapsedTimeF32(); + if (seconds >= app_metrics_interval) + { + metricsSend(! gDisconnected); + report_interval.reset(); + } + } // Update layonts, handle mouse events, tooltips, e t c @@ -4847,335 +4847,335 @@ void LLAppViewer::idle() // opening chat. gViewerWindow->updateUI(); - if (gDisconnected) + if (gDisconnected) { - return; + return; } - if (gTeleportDisplay) + if (gTeleportDisplay) { - return; + return; } - /////////////////////////////////////// - // Agent and camera movement - // - LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); + /////////////////////////////////////// + // Agent and camera movement + // + LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); - { - // After agent and camera moved, figure out if we need to - // deselect objects. - LLSelectMgr::getInstance()->deselectAllIfTooFar(); + { + // After agent and camera moved, figure out if we need to + // deselect objects. + LLSelectMgr::getInstance()->deselectAllIfTooFar(); - } + } - { - // Handle pending gesture processing - LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); - LLGestureMgr::instance().update(); + { + // Handle pending gesture processing + LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); + LLGestureMgr::instance().update(); - gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); - } + gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); + } - { - LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); + { + LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); if (!(logoutRequestSent() && hasSavedFinalSnapshot())) - { - gObjectList.update(gAgent); - } - } - - ////////////////////////////////////// - // - // Deletes objects... - // Has to be done after doing idleUpdates (which can kill objects) - // - - { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP); - { - gObjectList.cleanDeadObjects(); - } - { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); - LLDrawable::cleanupDeadDrawables(); - } - } - - // - // After this point, in theory we should never see a dead object - // in the various object/drawable lists. - // - - ////////////////////////////////////// - // - // Update/send HUD effects - // - // At this point, HUD effects may clean up some references to - // dead objects. - // - - { - LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); - LLSelectMgr::getInstance()->updateEffects(); - LLHUDManager::getInstance()->cleanupEffects(); - LLHUDManager::getInstance()->sendEffects(); - } - - //////////////////////////////////////// - // - // Unpack layer data that we've received - // - - { - LL_RECORD_BLOCK_TIME(FTM_NETWORK); - gVLManager.unpackData(); - } - - ///////////////////////// - // - // Update surfaces, and surface textures as well. - // - - LLWorld::getInstance()->updateVisibilities(); - { - const F32 max_region_update_time = .001f; // 1ms - LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); - LLWorld::getInstance()->updateRegions(max_region_update_time); - } - - ///////////////////////// - // - // Update weather effects - // - - // Update wind vector - LLVector3 wind_position_region; - static LLVector3 average_wind; - - LLViewerRegion *regionp; - regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position - if (regionp) - { - gWindVec = regionp->mWind.getVelocity(wind_position_region); - - // Compute average wind and use to drive motion of water - - average_wind = regionp->mWind.getAverage(); - gSky.setWind(average_wind); - //LLVOWater::setWind(average_wind); - } - else - { - gWindVec.setVec(0.0f, 0.0f, 0.0f); - } - - ////////////////////////////////////// - // - // Sort and cull in the new renderer are moved to pipeline.cpp - // Here, particles are updated and drawables are moved. - // - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); - gPipeline.updateMove(); - } - - LLWorld::getInstance()->updateParticles(); - - if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) - { - gAgentPilot.moveCamera(); - } - else if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - LLViewerJoystick::getInstance()->moveFlycam(); - } - else - { - if (LLToolMgr::getInstance()->inBuildMode()) - { - LLViewerJoystick::getInstance()->moveObjects(); - } - - gAgentCamera.updateCamera(); - } - - // update media focus - LLViewerMediaFocus::getInstance()->update(); - - // Update marketplace - LLMarketplaceInventoryImporter::update(); - LLMarketplaceInventoryNotifications::update(); - - // objects and camera should be in sync, do LOD calculations now - { - LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); - gObjectList.updateApparentAngles(gAgent); - } - - // Update AV render info - LLAvatarRenderInfoAccountant::getInstance()->idle(); - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); - - if (gAudiop) - { - audio_update_volume(false); - audio_update_listener(); - audio_update_wind(false); - - // this line actually commits the changes we've made to source positions, etc. - gAudiop->idle(); - } - } - - // Handle shutdown process, for example, - // wait for floaters to close, send quit message, - // forcibly quit if it has taken too long - if (mQuitRequested) - { - gGLActive = TRUE; - idleShutdown(); - } + { + gObjectList.update(gAgent); + } + } + + ////////////////////////////////////// + // + // Deletes objects... + // Has to be done after doing idleUpdates (which can kill objects) + // + + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP); + { + gObjectList.cleanDeadObjects(); + } + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); + LLDrawable::cleanupDeadDrawables(); + } + } + + // + // After this point, in theory we should never see a dead object + // in the various object/drawable lists. + // + + ////////////////////////////////////// + // + // Update/send HUD effects + // + // At this point, HUD effects may clean up some references to + // dead objects. + // + + { + LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); + LLSelectMgr::getInstance()->updateEffects(); + LLHUDManager::getInstance()->cleanupEffects(); + LLHUDManager::getInstance()->sendEffects(); + } + + //////////////////////////////////////// + // + // Unpack layer data that we've received + // + + { + LL_RECORD_BLOCK_TIME(FTM_NETWORK); + gVLManager.unpackData(); + } + + ///////////////////////// + // + // Update surfaces, and surface textures as well. + // + + LLWorld::getInstance()->updateVisibilities(); + { + const F32 max_region_update_time = .001f; // 1ms + LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); + LLWorld::getInstance()->updateRegions(max_region_update_time); + } + + ///////////////////////// + // + // Update weather effects + // + + // Update wind vector + LLVector3 wind_position_region; + static LLVector3 average_wind; + + LLViewerRegion *regionp; + regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position + if (regionp) + { + gWindVec = regionp->mWind.getVelocity(wind_position_region); + + // Compute average wind and use to drive motion of water + + average_wind = regionp->mWind.getAverage(); + gSky.setWind(average_wind); + //LLVOWater::setWind(average_wind); + } + else + { + gWindVec.setVec(0.0f, 0.0f, 0.0f); + } + + ////////////////////////////////////// + // + // Sort and cull in the new renderer are moved to pipeline.cpp + // Here, particles are updated and drawables are moved. + // + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); + gPipeline.updateMove(); + } + + LLWorld::getInstance()->updateParticles(); + + if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera()) + { + gAgentPilot.moveCamera(); + } + else if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + LLViewerJoystick::getInstance()->moveFlycam(); + } + else + { + if (LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveObjects(); + } + + gAgentCamera.updateCamera(); + } + + // update media focus + LLViewerMediaFocus::getInstance()->update(); + + // Update marketplace + LLMarketplaceInventoryImporter::update(); + LLMarketplaceInventoryNotifications::update(); + + // objects and camera should be in sync, do LOD calculations now + { + LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); + gObjectList.updateApparentAngles(gAgent); + } + + // Update AV render info + LLAvatarRenderInfoAccountant::getInstance()->idle(); + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); + + if (gAudiop) + { + audio_update_volume(false); + audio_update_listener(); + audio_update_wind(false); + + // this line actually commits the changes we've made to source positions, etc. + gAudiop->idle(); + } + } + + // Handle shutdown process, for example, + // wait for floaters to close, send quit message, + // forcibly quit if it has taken too long + if (mQuitRequested) + { + gGLActive = TRUE; + idleShutdown(); + } } void LLAppViewer::idleShutdown() { - // Wait for all modal alerts to get resolved - if (LLModalDialog::activeCount() > 0) - { - return; - } - - // close IM interface - if(gIMMgr) - { - gIMMgr->disconnectAllSessions(); - } - - // Wait for all floaters to get resolved - if (gFloaterView - && !gFloaterView->allChildrenClosed()) - { - return; - } - - - - - // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup() - // *TODO: ugly - static bool saved_teleport_history = false; - if (!saved_teleport_history) - { - saved_teleport_history = true; - LLTeleportHistory::getInstance()->dump(); - LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this - return; - } - - static bool saved_snapshot = false; - if (!saved_snapshot) - { - saved_snapshot = true; - saveFinalSnapshot(); - return; - } - - const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f; - - S32 pending_uploads = gAssetStorage->getNumPendingUploads(); - if (pending_uploads > 0 - && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME - && !logoutRequestSent()) - { - static S32 total_uploads = 0; - // Sometimes total upload count can change during logout. - total_uploads = llmax(total_uploads, pending_uploads); - gViewerWindow->setShowProgress(TRUE); - S32 finished_uploads = total_uploads - pending_uploads; - F32 percent = 100.f * finished_uploads / total_uploads; - gViewerWindow->setProgressPercent(percent); - gViewerWindow->setProgressString(LLTrans::getString("SavingSettings")); - return; - } - - if (gPendingMetricsUploads > 0 - && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME - && !logoutRequestSent()) - { + // Wait for all modal alerts to get resolved + if (LLModalDialog::activeCount() > 0) + { + return; + } + + // close IM interface + if(gIMMgr) + { + gIMMgr->disconnectAllSessions(); + } + + // Wait for all floaters to get resolved + if (gFloaterView + && !gFloaterView->allChildrenClosed()) + { + return; + } + + + + + // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup() + // *TODO: ugly + static bool saved_teleport_history = false; + if (!saved_teleport_history) + { + saved_teleport_history = true; + LLTeleportHistory::getInstance()->dump(); + LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this + return; + } + + static bool saved_snapshot = false; + if (!saved_snapshot) + { + saved_snapshot = true; + saveFinalSnapshot(); + return; + } + + const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f; + + S32 pending_uploads = gAssetStorage->getNumPendingUploads(); + if (pending_uploads > 0 + && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME + && !logoutRequestSent()) + { + static S32 total_uploads = 0; + // Sometimes total upload count can change during logout. + total_uploads = llmax(total_uploads, pending_uploads); + gViewerWindow->setShowProgress(TRUE); + S32 finished_uploads = total_uploads - pending_uploads; + F32 percent = 100.f * finished_uploads / total_uploads; + gViewerWindow->setProgressPercent(percent); + gViewerWindow->setProgressString(LLTrans::getString("SavingSettings")); + return; + } + + if (gPendingMetricsUploads > 0 + && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME + && !logoutRequestSent()) + { gViewerWindow->setShowProgress(TRUE); gViewerWindow->setProgressPercent(100.f); gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); - return; - } - - // All floaters are closed. Tell server we want to quit. - if( !logoutRequestSent() ) - { - sendLogoutRequest(); - - // Wait for a LogoutReply message - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressPercent(100.f); - gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); - return; - } - - // Make sure that we quit if we haven't received a reply from the server. - if( logoutRequestSent() - && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime ) - { - forceQuit(); - return; - } + return; + } + + // All floaters are closed. Tell server we want to quit. + if( !logoutRequestSent() ) + { + sendLogoutRequest(); + + // Wait for a LogoutReply message + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressPercent(100.f); + gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); + return; + } + + // Make sure that we quit if we haven't received a reply from the server. + if( logoutRequestSent() + && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime ) + { + forceQuit(); + return; + } } void LLAppViewer::sendLogoutRequest() { - if(!mLogoutRequestSent && gMessageSystem) - { - //Set internal status variables and marker files before actually starting the logout process - gLogoutInProgress = TRUE; - if (!mSecondInstance) - { - mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); - - mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB); - if (mLogoutMarkerFile.getFileHandle()) - { - LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL; - recordMarkerVersion(mLogoutMarkerFile); - } - else - { - LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "Did not logout marker file because this is a second instance" << LL_ENDL; - } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_LogoutRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - - gLogoutTimer.reset(); - gLogoutMaxTime = LOGOUT_REQUEST_TIME; - mLogoutRequestSent = TRUE; - - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->leaveChannel(); - } - } + if(!mLogoutRequestSent && gMessageSystem) + { + //Set internal status variables and marker files before actually starting the logout process + gLogoutInProgress = TRUE; + if (!mSecondInstance) + { + mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); + + mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB); + if (mLogoutMarkerFile.getFileHandle()) + { + LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL; + recordMarkerVersion(mLogoutMarkerFile); + } + else + { + LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Did not logout marker file because this is a second instance" << LL_ENDL; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LogoutRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + + gLogoutTimer.reset(); + gLogoutMaxTime = LOGOUT_REQUEST_TIME; + mLogoutRequestSent = TRUE; + + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->leaveChannel(); + } + } } void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) @@ -5221,19 +5221,19 @@ void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) void LLAppViewer::idleNameCache() { - // Neither old nor new name cache can function before agent has a region - LLViewerRegion* region = gAgent.getRegion(); + // Neither old nor new name cache can function before agent has a region + LLViewerRegion* region = gAgent.getRegion(); if (!region) { return; } - // deal with any queued name requests and replies. - gCacheName->processPending(); + // deal with any queued name requests and replies. + gCacheName->processPending(); - // Can't run the new cache until we have the list of capabilities - // for the agent region, and can therefore decide whether to use - // display names or fall back to the old name system. + // Can't run the new cache until we have the list of capabilities + // for the agent region, and can therefore decide whether to use + // display names or fall back to the old name system. if (!region->capabilitiesReceived()) { return; @@ -5263,141 +5263,141 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ void LLAppViewer::idleNetwork() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - pingMainloopTimeout("idleNetwork"); - - gObjectList.mNumNewObjects = 0; - S32 total_decoded = 0; - - if (!gSavedSettings.getBOOL("SpeedTest")) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode - - LLTimer check_message_timer; - // Read all available packets from network - const S64 frame_count = gFrameCount; // U32->S64 - F32 total_time = 0.0f; - - { - LockMessageChecker lmc(gMessageSystem); - while (lmc.checkAllMessages(frame_count, gServicePump)) - { - if (gDoDisconnect) - { - // We're disconnecting, don't process any more messages from the server - // We're usually disconnecting due to either network corruption or a - // server going down, so this is OK. - break; - } - - total_decoded++; - gPacketsIn++; - - if (total_decoded > MESSAGE_MAX_PER_FRAME) - { - break; - } + pingMainloopTimeout("idleNetwork"); + + gObjectList.mNumNewObjects = 0; + S32 total_decoded = 0; + + if (!gSavedSettings.getBOOL("SpeedTest")) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode + + LLTimer check_message_timer; + // Read all available packets from network + const S64 frame_count = gFrameCount; // U32->S64 + F32 total_time = 0.0f; + + { + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(frame_count, gServicePump)) + { + if (gDoDisconnect) + { + // We're disconnecting, don't process any more messages from the server + // We're usually disconnecting due to either network corruption or a + // server going down, so this is OK. + break; + } + + total_decoded++; + gPacketsIn++; + + if (total_decoded > MESSAGE_MAX_PER_FRAME) + { + break; + } #ifdef TIME_THROTTLE_MESSAGES - // Prevent slow packets from completely destroying the frame rate. - // This usually happens due to clumps of avatars taking huge amount - // of network processing time (which needs to be fixed, but this is - // a good limit anyway). - total_time = check_message_timer.getElapsedTimeF32(); - if (total_time >= CheckMessagesMaxTime) - break; + // Prevent slow packets from completely destroying the frame rate. + // This usually happens due to clumps of avatars taking huge amount + // of network processing time (which needs to be fixed, but this is + // a good limit anyway). + total_time = check_message_timer.getElapsedTimeF32(); + if (total_time >= CheckMessagesMaxTime) + break; #endif - } + } - // Handle per-frame message system processing. - lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); - } + // Handle per-frame message system processing. + lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); + } #ifdef TIME_THROTTLE_MESSAGES - if (total_time >= CheckMessagesMaxTime) - { - // Increase CheckMessagesMaxTime so that we will eventually catch up - CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames - } - else - { - // Reset CheckMessagesMaxTime to default value - CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; - } + if (total_time >= CheckMessagesMaxTime) + { + // Increase CheckMessagesMaxTime so that we will eventually catch up + CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames + } + else + { + // Reset CheckMessagesMaxTime to default value + CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; + } #endif - // we want to clear the control after sending out all necessary agent updates - gAgent.resetControlFlags(); - - // Decode enqueued messages... - S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded; - - if( remaining_possible_decodes <= 0 ) - { - LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; - } - - if (gPrintMessagesThisFrame) - { - LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; - gPrintMessagesThisFrame = FALSE; - } - } - add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); - - // Retransmit unacknowledged packets. - gXferManager->retransmitUnackedPackets(); - gAssetStorage->checkForTimeouts(); - gViewerThrottle.updateDynamicThrottle(); - - // Check that the circuit between the viewer and the agent's current - // region is still alive - LLViewerRegion *agent_region = gAgent.getRegion(); - if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) - { - LLUUID this_region_id = agent_region->getRegionID(); - bool this_region_alive = agent_region->isAlive(); - if ((mAgentRegionLastAlive && !this_region_alive) // newly dead - && (mAgentRegionLastID == this_region_id)) // same region - { - forceDisconnect(LLTrans::getString("AgentLostConnection")); - } - mAgentRegionLastID = this_region_id; - mAgentRegionLastAlive = this_region_alive; - } + // we want to clear the control after sending out all necessary agent updates + gAgent.resetControlFlags(); + + // Decode enqueued messages... + S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded; + + if( remaining_possible_decodes <= 0 ) + { + LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; + } + + if (gPrintMessagesThisFrame) + { + LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; + gPrintMessagesThisFrame = FALSE; + } + } + add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); + + // Retransmit unacknowledged packets. + gXferManager->retransmitUnackedPackets(); + gAssetStorage->checkForTimeouts(); + gViewerThrottle.updateDynamicThrottle(); + + // Check that the circuit between the viewer and the agent's current + // region is still alive + LLViewerRegion *agent_region = gAgent.getRegion(); + if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) + { + LLUUID this_region_id = agent_region->getRegionID(); + bool this_region_alive = agent_region->isAlive(); + if ((mAgentRegionLastAlive && !this_region_alive) // newly dead + && (mAgentRegionLastID == this_region_id)) // same region + { + forceDisconnect(LLTrans::getString("AgentLostConnection")); + } + mAgentRegionLastID = this_region_id; + mAgentRegionLastAlive = this_region_alive; + } } void LLAppViewer::disconnectViewer() { - if (gDisconnected) - { - return; - } - // - // Cleanup after quitting. - // - // Save snapshot for next time, if we made it through initialization - - LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; - - // Dump our frame statistics - - // Remember if we were flying - gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); - - // Un-minimize all windows so they don't get saved minimized - if (gFloaterView) - { - gFloaterView->restoreAll(); - } - - if (LLSelectMgr::instanceExists()) - { - LLSelectMgr::getInstance()->deselectAll(); - } - - // save inventory if appropriate + if (gDisconnected) + { + return; + } + // + // Cleanup after quitting. + // + // Save snapshot for next time, if we made it through initialization + + LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; + + // Dump our frame statistics + + // Remember if we were flying + gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); + + // Un-minimize all windows so they don't get saved minimized + if (gFloaterView) + { + gFloaterView->restoreAll(); + } + + if (LLSelectMgr::instanceExists()) + { + LLSelectMgr::getInstance()->deselectAll(); + } + + // save inventory if appropriate if (gInventory.isInventoryUsable() && gAgent.getID().notNull()) // Shouldn't be null at this stage { @@ -5412,44 +5412,44 @@ void LLAppViewer::disconnectViewer() } } - saveNameCache(); - if (LLExperienceCache::instanceExists()) - { - // TODO: LLExperienceCache::cleanup() logic should be moved to - // cleanupSingleton(). - LLExperienceCache::instance().cleanup(); - } + saveNameCache(); + if (LLExperienceCache::instanceExists()) + { + // TODO: LLExperienceCache::cleanup() logic should be moved to + // cleanupSingleton(). + LLExperienceCache::instance().cleanup(); + } - // close inventory interface, close all windows - LLSidepanelInventory::cleanup(); + // close inventory interface, close all windows + LLSidepanelInventory::cleanup(); - gAgentWearables.cleanup(); - gAgentCamera.cleanup(); - // Also writes cached agent settings to gSavedSettings - gAgent.cleanup(); + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + // Also writes cached agent settings to gSavedSettings + gAgent.cleanup(); - // This is where we used to call gObjectList.destroy() and then delete gWorldp. - // Now we just ask the LLWorld singleton to cleanly shut down. - if(LLWorld::instanceExists()) - { - LLWorld::getInstance()->resetClass(); - } - LLVOCache::deleteSingleton(); + // This is where we used to call gObjectList.destroy() and then delete gWorldp. + // Now we just ask the LLWorld singleton to cleanly shut down. + if(LLWorld::instanceExists()) + { + LLWorld::getInstance()->resetClass(); + } + LLVOCache::deleteSingleton(); - // call all self-registered classes - LLDestroyClassList::instance().fireCallbacks(); + // call all self-registered classes + LLDestroyClassList::instance().fireCallbacks(); - cleanup_xfer_manager(); - gDisconnected = TRUE; + cleanup_xfer_manager(); + gDisconnected = TRUE; - // Pass the connection state to LLUrlEntryParcel not to attempt - // parcel info requests while disconnected. - LLUrlEntryParcel::setDisconnected(gDisconnected); + // Pass the connection state to LLUrlEntryParcel not to attempt + // parcel info requests while disconnected. + LLUrlEntryParcel::setDisconnected(gDisconnected); } void LLAppViewer::forceErrorLLError() { - LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; + LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; } void LLAppViewer::forceErrorLLErrorMsg() @@ -5462,7 +5462,7 @@ void LLAppViewer::forceErrorLLErrorMsg() void LLAppViewer::forceErrorBreakpoint() { - LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; #ifdef LL_WINDOWS DebugBreak(); #else @@ -5473,7 +5473,7 @@ void LLAppViewer::forceErrorBreakpoint() void LLAppViewer::forceErrorBadMemoryAccess() { - LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; S32* crash = NULL; *crash = 0xDEADBEEF; return; @@ -5481,7 +5481,7 @@ void LLAppViewer::forceErrorBadMemoryAccess() void LLAppViewer::forceErrorInfiniteLoop() { - LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; // Loop is intentionally complicated to fool basic loop detection LLTimer timer_total; LLTimer timer_expiry; @@ -5500,7 +5500,7 @@ void LLAppViewer::forceErrorInfiniteLoop() void LLAppViewer::forceErrorSoftwareException() { - LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; + LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; LLTHROW(LLException("User selected Force Software Exception")); } @@ -5513,8 +5513,8 @@ void LLAppViewer::forceErrorOSSpecificException() void LLAppViewer::forceErrorDriverCrash() { - LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; - glDeleteTextures(1, NULL); + LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; + glDeleteTextures(1, NULL); } void LLAppViewer::forceErrorCoroutineCrash() @@ -5546,120 +5546,120 @@ void LLAppViewer::forceErrorThreadCrash() void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) { - if(!mMainloopTimeout) - { - mMainloopTimeout = new LLWatchdogTimeout(); - resumeMainloopTimeout(state, secs); - } + if(!mMainloopTimeout) + { + mMainloopTimeout = new LLWatchdogTimeout(); + resumeMainloopTimeout(state, secs); + } } void LLAppViewer::destroyMainloopTimeout() { - if(mMainloopTimeout) - { - delete mMainloopTimeout; - mMainloopTimeout = NULL; - } + if(mMainloopTimeout) + { + delete mMainloopTimeout; + mMainloopTimeout = NULL; + } } void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) { - if(mMainloopTimeout) - { - if(secs < 0.0f) - { - static LLCachedControl mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); - secs = mainloop_timeout; - } - - mMainloopTimeout->setTimeout(secs); - mMainloopTimeout->start(state); - } + if(mMainloopTimeout) + { + if(secs < 0.0f) + { + static LLCachedControl mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; + } + + mMainloopTimeout->setTimeout(secs); + mMainloopTimeout->start(state); + } } void LLAppViewer::pauseMainloopTimeout() { - if(mMainloopTimeout) - { - mMainloopTimeout->stop(); - } + if(mMainloopTimeout) + { + mMainloopTimeout->stop(); + } } void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) { LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - if(mMainloopTimeout) - { - if(secs < 0.0f) - { - static LLCachedControl mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); - secs = mainloop_timeout; - } - - mMainloopTimeout->setTimeout(secs); - mMainloopTimeout->ping(state); - } + if(mMainloopTimeout) + { + if(secs < 0.0f) + { + static LLCachedControl mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; + } + + mMainloopTimeout->setTimeout(secs); + mMainloopTimeout->ping(state); + } } void LLAppViewer::handleLoginComplete() { - gLoggedInTime.start(); - initMainloopTimeout("Mainloop Init"); - - // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if ( parcel && parcel->getMusicURL()[0]) - { - gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); - } - if ( parcel && parcel->getMediaURL()[0]) - { - gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); - } - - gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); - gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); - gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); - gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - - if(gAgent.getRegion()) - { - gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); - gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); - } - - if(LLAppViewer::instance()->mMainloopTimeout) - { - gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); - } - - mOnLoginCompleted(); - - writeDebugInfo(); - - // we logged in successfully, so save settings on logout - LL_INFOS() << "Login successful, per account settings will be saved on log out." << LL_ENDL; - mSavePerAccountSettings=true; + gLoggedInTime.start(); + initMainloopTimeout("Mainloop Init"); + + // Store some data to DebugInfo in case of a freeze. + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if ( parcel && parcel->getMusicURL()[0]) + { + gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); + } + if ( parcel && parcel->getMediaURL()[0]) + { + gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); + } + + gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); + + if(gAgent.getRegion()) + { + gDebugInfo["CurrentSimHost"] = gAgent.getRegion()->getSimHostName(); + gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); + } + + if(LLAppViewer::instance()->mMainloopTimeout) + { + gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); + } + + mOnLoginCompleted(); + + writeDebugInfo(); + + // we logged in successfully, so save settings on logout + LL_INFOS() << "Login successful, per account settings will be saved on log out." << LL_ENDL; + mSavePerAccountSettings=true; } //virtual void LLAppViewer::setMasterSystemAudioMute(bool mute) { - gSavedSettings.setBOOL("MuteAudio", mute); + gSavedSettings.setBOOL("MuteAudio", mute); } //virtual bool LLAppViewer::getMasterSystemAudioMute() { - return gSavedSettings.getBOOL("MuteAudio"); + return gSavedSettings.getBOOL("MuteAudio"); } //---------------------------------------------------------------------------- @@ -5675,10 +5675,10 @@ bool LLAppViewer::getMasterSystemAudioMute() */ void LLAppViewer::metricsUpdateRegion(U64 region_handle) { - if (0 != region_handle) - { - LLViewerAssetStatsFF::set_region(region_handle); - } + if (0 != region_handle) + { + LLViewerAssetStatsFF::set_region(region_handle); + } } /** @@ -5687,35 +5687,35 @@ void LLAppViewer::metricsUpdateRegion(U64 region_handle) */ void LLAppViewer::metricsSend(bool enable_reporting) { - if (! gViewerAssetStats) - return; + if (! gViewerAssetStats) + return; - if (LLAppViewer::sTextureFetch) - { - LLViewerRegion * regionp = gAgent.getRegion(); + if (LLAppViewer::sTextureFetch) + { + LLViewerRegion * regionp = gAgent.getRegion(); - if (enable_reporting && regionp) - { - std::string caps_url = regionp->getCapability("ViewerMetrics"); + if (enable_reporting && regionp) + { + std::string caps_url = regionp->getCapability("ViewerMetrics"); LLSD sd = gViewerAssetStats->asLLSD(true); - // Send a report request into 'thread1' to get the rest of the data - // and provide some additional parameters while here. - LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, - gAgentSessionID, - gAgentID, - sd); - } - else - { - LLAppViewer::sTextureFetch->commandDataBreak(); - } - } - - // Reset even if we can't report. Rather than gather up a huge chunk of - // data, we'll keep to our sampling interval and retain the data - // resolution in time. - gViewerAssetStats->restart(); + // Send a report request into 'thread1' to get the rest of the data + // and provide some additional parameters while here. + LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, + gAgentSessionID, + gAgentID, + sd); + } + else + { + LLAppViewer::sTextureFetch->commandDataBreak(); + } + } + + // Reset even if we can't report. Rather than gather up a huge chunk of + // data, we'll keep to our sampling interval and retain the data + // resolution in time. + gViewerAssetStats->restart(); } diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 93a0ef0e82..b4ced668d0 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldonotdisturbnotificationstorage.cpp * @brief Implementation of lldonotdisturbnotificationstorage * @author Stinson@lindenlab.com @@ -68,7 +68,7 @@ bool LLDoNotDisturbNotificationStorageTimer::tick() } LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage() - : LLNotificationStorage("") + : LLNotificationStorage("") , mDirty(false) { nameToPayloadParameterMap[toastName] = "SESSION_ID"; @@ -88,7 +88,7 @@ void LLDoNotDisturbNotificationStorage::reset() void LLDoNotDisturbNotificationStorage::initialize() { reset(); - getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1)); + getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1)); } bool LLDoNotDisturbNotificationStorage::getDirty() @@ -105,27 +105,27 @@ void LLDoNotDisturbNotificationStorage::saveNotifications() { LL_PROFILE_ZONE_SCOPED; - LLNotificationChannelPtr channelPtr = getCommunicationChannel(); - const LLCommunicationChannel *commChannel = dynamic_cast(channelPtr.get()); - llassert(commChannel != NULL); + LLNotificationChannelPtr channelPtr = getCommunicationChannel(); + const LLCommunicationChannel *commChannel = dynamic_cast(channelPtr.get()); + llassert(commChannel != NULL); - LLSD output = LLSD::emptyMap(); - LLSD& data = output["data"]; - data = LLSD::emptyArray(); + LLSD output = LLSD::emptyMap(); + LLSD& data = output["data"]; + data = LLSD::emptyArray(); - for (LLCommunicationChannel::history_list_t::const_iterator historyIter = commChannel->beginHistory(); - historyIter != commChannel->endHistory(); ++historyIter) - { - LLNotificationPtr notificationPtr = historyIter->second; + for (LLCommunicationChannel::history_list_t::const_iterator historyIter = commChannel->beginHistory(); + historyIter != commChannel->endHistory(); ++historyIter) + { + LLNotificationPtr notificationPtr = historyIter->second; - if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && - !notificationPtr->isExpired() && !notificationPtr->isPersistent()) - { - data.append(notificationPtr->asLLSD(true)); - } - } + if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && + !notificationPtr->isExpired() && !notificationPtr->isPersistent()) + { + data.append(notificationPtr->asLLSD(true)); + } + } - writeNotifications(output); + writeNotifications(output); resetDirty(); } @@ -134,114 +134,114 @@ static LLTrace::BlockTimerStatHandle FTM_LOAD_DND_NOTIFICATIONS("Load DND Notifi void LLDoNotDisturbNotificationStorage::loadNotifications() { - LL_RECORD_BLOCK_TIME(FTM_LOAD_DND_NOTIFICATIONS); - - LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL; - - LLSD input; - if (!readNotifications(input) ||input.isUndefined()) - { - return; - } - - LLSD& data = input["data"]; - if (data.isUndefined()) - { - return; - } - - LLNotifications& instance = LLNotifications::instance(); + LL_RECORD_BLOCK_TIME(FTM_LOAD_DND_NOTIFICATIONS); + + LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL; + + LLSD input; + if (!readNotifications(input) ||input.isUndefined()) + { + return; + } + + LLSD& data = input["data"]; + if (data.isUndefined()) + { + return; + } + + LLNotifications& instance = LLNotifications::instance(); bool imToastExists = false; - bool group_ad_hoc_toast_exists = false; - S32 toastSessionType; + bool group_ad_hoc_toast_exists = false; + S32 toastSessionType; bool offerExists = false; - - for (LLSD::array_const_iterator notification_it = data.beginArray(); - notification_it != data.endArray(); - ++notification_it) - { - LLSD notification_params = *notification_it; + + for (LLSD::array_const_iterator notification_it = data.beginArray(); + notification_it != data.endArray(); + ++notification_it) + { + LLSD notification_params = *notification_it; const LLUUID& notificationID = notification_params["id"]; std::string notificationName = notification_params["name"]; LLNotificationPtr notification = instance.find(notificationID); if(notificationName == toastName) { - toastSessionType = notification_params["payload"]["SESSION_TYPE"]; - if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION) - { - imToastExists = true; - } - //Don't add group/ad-hoc messages to the notification system because - //this means the group/ad-hoc session has to be re-created - else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION - || toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION) - { - //Just allows opening the conversation log for group/ad-hoc messages upon startup - group_ad_hoc_toast_exists = true; - continue; - } + toastSessionType = notification_params["payload"]["SESSION_TYPE"]; + if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION) + { + imToastExists = true; + } + //Don't add group/ad-hoc messages to the notification system because + //this means the group/ad-hoc session has to be re-created + else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION + || toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION) + { + //Just allows opening the conversation log for group/ad-hoc messages upon startup + group_ad_hoc_toast_exists = true; + continue; + } } else if(notificationName == offerName) { offerExists = true; } - - //Notification already exists due to persistent storage adding it first into the notification system - if(notification) - { - notification->setDND(true); - instance.update(instance.find(notificationID)); - } - //New notification needs to be added - else - { - notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true)); - LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]); - if (responder == NULL) - { - LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '" - << notification->getType() << "'" << LL_ENDL; - } - else - { - LLNotificationResponderPtr responderPtr(responder); - notification->setResponseFunctor(responderPtr); - } - - instance.add(notification); - } - - } + + //Notification already exists due to persistent storage adding it first into the notification system + if(notification) + { + notification->setDND(true); + instance.update(instance.find(notificationID)); + } + //New notification needs to be added + else + { + notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true)); + LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]); + if (responder == NULL) + { + LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '" + << notification->getType() << "'" << LL_ENDL; + } + else + { + LLNotificationResponderPtr responderPtr(responder); + notification->setResponseFunctor(responderPtr); + } + + instance.add(notification); + } + + } bool isConversationLoggingAllowed = gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0; - if(group_ad_hoc_toast_exists && isConversationLoggingAllowed) - { - LLFloaterReg::showInstance("conversation"); - } + if(group_ad_hoc_toast_exists && isConversationLoggingAllowed) + { + LLFloaterReg::showInstance("conversation"); + } if(imToastExists || group_ad_hoc_toast_exists || offerExists) { - make_ui_sound_deferred("UISndNewIncomingIMSession"); + make_ui_sound_deferred("UISndNewIncomingIMSession"); } //writes out empty .xml file (since LLCommunicationChannel::mHistory is empty) - saveNotifications(); + saveNotifications(); - LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL; + LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL; } void LLDoNotDisturbNotificationStorage::updateNotifications() { - LLNotificationChannelPtr channelPtr = getCommunicationChannel(); - LLCommunicationChannel *commChannel = dynamic_cast(channelPtr.get()); - llassert(commChannel != NULL); + LLNotificationChannelPtr channelPtr = getCommunicationChannel(); + LLCommunicationChannel *commChannel = dynamic_cast(channelPtr.get()); + llassert(commChannel != NULL); LLNotifications& instance = LLNotifications::instance(); bool imToastExists = false; bool offerExists = false; - + for (LLCommunicationChannel::history_list_t::const_iterator it = commChannel->beginHistory(); it != commChannel->endHistory(); ++it) @@ -274,16 +274,16 @@ void LLDoNotDisturbNotificationStorage::updateNotifications() //When exit DND mode, write empty notifications file if(commChannel->getHistorySize()) { - commChannel->clearHistory(); - saveNotifications(); + commChannel->clearHistory(); + saveNotifications(); } } LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChannel() const { - LLNotificationChannelPtr channelPtr = LLNotifications::getInstance()->getChannel("Communication"); - llassert(channelPtr); - return channelPtr; + LLNotificationChannelPtr channelPtr = LLNotifications::getInstance()->getChannel("Communication"); + llassert(channelPtr); + return channelPtr; } void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, const LLUUID& id) @@ -301,7 +301,7 @@ void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, co //Find notification with the matching session id for (it = commChannel->beginHistory(); - it != commChannel->endHistory(); + it != commChannel->endHistory(); ++it) { notification = it->second; @@ -336,10 +336,10 @@ void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, co bool LLDoNotDisturbNotificationStorage::onChannelChanged(const LLSD& pPayload) { - if (pPayload["sigtype"].asString() != "load") - { + if (pPayload["sigtype"].asString() != "load") + { mDirty = true; - } + } - return false; + return false; } diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index 2d39b5efed..0dc2515e02 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -1,4 +1,4 @@ -/** +/** * @file lldonotdisturbnotificationstorage.h * @brief Header file for lldonotdisturbnotificationstorage * @author Stinson@lindenlab.com @@ -47,18 +47,18 @@ public: class LLDoNotDisturbNotificationStorage : public LLParamSingleton, public LLNotificationStorage { - LLSINGLETON(LLDoNotDisturbNotificationStorage); - ~LLDoNotDisturbNotificationStorage(); + LLSINGLETON(LLDoNotDisturbNotificationStorage); + ~LLDoNotDisturbNotificationStorage(); - LOG_CLASS(LLDoNotDisturbNotificationStorage); + LOG_CLASS(LLDoNotDisturbNotificationStorage); public: static const char * toastName; static const char * offerName; bool getDirty(); void resetDirty(); - void saveNotifications(); - void loadNotifications(); + void saveNotifications(); + void loadNotifications(); void updateNotifications(); void removeNotification(const char * name, const LLUUID& id); void reset(); @@ -71,8 +71,8 @@ private: bool mDirty; LLDoNotDisturbNotificationStorageTimer mTimer; - LLNotificationChannelPtr getCommunicationChannel() const; - bool onChannelChanged(const LLSD& pPayload); + LLNotificationChannelPtr getCommunicationChannel() const; + bool onChannelChanged(const LLSD& pPayload); std::map nameToPayloadParameterMap; }; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 68952c96c5..e654caf1b2 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ #include "llframetimer.h" #include "lltrans.h" #include "llviewercontrol.h" -#include "llwindow.h" // beforeDialog() +#include "llwindow.h" // beforeDialog() #if LL_SDL #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers @@ -76,149 +76,149 @@ LLFilePicker LLFilePicker::sInstance; // Implementation // LLFilePicker::LLFilePicker() - : mCurrentFile(0), - mLocked(false) + : mCurrentFile(0), + mLocked(false) { - reset(); + reset(); #if LL_WINDOWS - mOFN.lStructSize = sizeof(OPENFILENAMEW); - mOFN.hwndOwner = NULL; // Set later - mOFN.hInstance = NULL; - mOFN.lpstrCustomFilter = NULL; - mOFN.nMaxCustFilter = 0; - mOFN.lpstrFile = NULL; // set in open and close - mOFN.nMaxFile = LL_MAX_PATH; - mOFN.lpstrFileTitle = NULL; - mOFN.nMaxFileTitle = 0; - mOFN.lpstrInitialDir = NULL; - mOFN.lpstrTitle = NULL; - mOFN.Flags = 0; // set in open and close - mOFN.nFileOffset = 0; - mOFN.nFileExtension = 0; - mOFN.lpstrDefExt = NULL; - mOFN.lCustData = 0L; - mOFN.lpfnHook = NULL; - mOFN.lpTemplateName = NULL; - mFilesW[0] = '\0'; + mOFN.lStructSize = sizeof(OPENFILENAMEW); + mOFN.hwndOwner = NULL; // Set later + mOFN.hInstance = NULL; + mOFN.lpstrCustomFilter = NULL; + mOFN.nMaxCustFilter = 0; + mOFN.lpstrFile = NULL; // set in open and close + mOFN.nMaxFile = LL_MAX_PATH; + mOFN.lpstrFileTitle = NULL; + mOFN.nMaxFileTitle = 0; + mOFN.lpstrInitialDir = NULL; + mOFN.lpstrTitle = NULL; + mOFN.Flags = 0; // set in open and close + mOFN.nFileOffset = 0; + mOFN.nFileExtension = 0; + mOFN.lpstrDefExt = NULL; + mOFN.lCustData = 0L; + mOFN.lpfnHook = NULL; + mOFN.lpTemplateName = NULL; + mFilesW[0] = '\0'; #elif LL_DARWIN - mPickOptions = 0; + mPickOptions = 0; #endif } LLFilePicker::~LLFilePicker() { - // nothing + // nothing } -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLFilePicker::check_local_file_access_enabled() { - // if local file browsing is turned off, return without opening dialog - bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled"); - if ( ! local_file_system_browsing_enabled ) - { - mFiles.clear(); - return false; - } - - return true; + // if local file browsing is turned off, return without opening dialog + bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled"); + if ( ! local_file_system_browsing_enabled ) + { + mFiles.clear(); + return false; + } + + return true; } const std::string LLFilePicker::getFirstFile() { - mCurrentFile = 0; - return getNextFile(); + mCurrentFile = 0; + return getNextFile(); } const std::string LLFilePicker::getNextFile() { - if (mCurrentFile >= getFileCount()) - { - mLocked = false; - return std::string(); - } - else - { - return mFiles[mCurrentFile++]; - } + if (mCurrentFile >= getFileCount()) + { + mLocked = false; + return std::string(); + } + else + { + return mFiles[mCurrentFile++]; + } } const std::string LLFilePicker::getCurFile() { - if (mCurrentFile >= getFileCount()) - { - mLocked = false; - return std::string(); - } - else - { - return mFiles[mCurrentFile]; - } + if (mCurrentFile >= getFileCount()) + { + mLocked = false; + return std::string(); + } + else + { + return mFiles[mCurrentFile]; + } } void LLFilePicker::reset() { - mLocked = false; - mFiles.clear(); - mCurrentFile = 0; + mLocked = false; + mFiles.clear(); + mCurrentFile = 0; } #if LL_WINDOWS BOOL LLFilePicker::setupFilter(ELoadFilter filter) { - BOOL res = TRUE; - switch (filter) - { + BOOL res = TRUE; + switch (filter) + { case FFLOAD_ALL: case FFLOAD_EXE: - mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ - SOUND_FILTER \ - IMAGE_FILTER \ - ANIM_FILTER \ - MATERIAL_FILTER \ - L"\0"; - break; - case FFLOAD_WAV: - mOFN.lpstrFilter = SOUND_FILTER \ - L"\0"; - break; - case FFLOAD_IMAGE: - mOFN.lpstrFilter = IMAGE_FILTER \ - L"\0"; - break; - case FFLOAD_ANIM: - mOFN.lpstrFilter = ANIM_FILTER \ - L"\0"; - break; - case FFLOAD_GLTF: - mOFN.lpstrFilter = GLTF_FILTER \ - L"\0"; - break; - case FFLOAD_COLLADA: - mOFN.lpstrFilter = COLLADA_FILTER \ - L"\0"; - break; - case FFLOAD_XML: - mOFN.lpstrFilter = XML_FILTER \ - L"\0"; - break; - case FFLOAD_SLOBJECT: - mOFN.lpstrFilter = SLOBJECT_FILTER \ - L"\0"; - break; - case FFLOAD_RAW: - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFLOAD_MODEL: - mOFN.lpstrFilter = MODEL_FILTER \ - L"\0"; - break; + mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ + SOUND_FILTER \ + IMAGE_FILTER \ + ANIM_FILTER \ + MATERIAL_FILTER \ + L"\0"; + break; + case FFLOAD_WAV: + mOFN.lpstrFilter = SOUND_FILTER \ + L"\0"; + break; + case FFLOAD_IMAGE: + mOFN.lpstrFilter = IMAGE_FILTER \ + L"\0"; + break; + case FFLOAD_ANIM: + mOFN.lpstrFilter = ANIM_FILTER \ + L"\0"; + break; + case FFLOAD_GLTF: + mOFN.lpstrFilter = GLTF_FILTER \ + L"\0"; + break; + case FFLOAD_COLLADA: + mOFN.lpstrFilter = COLLADA_FILTER \ + L"\0"; + break; + case FFLOAD_XML: + mOFN.lpstrFilter = XML_FILTER \ + L"\0"; + break; + case FFLOAD_SLOBJECT: + mOFN.lpstrFilter = SLOBJECT_FILTER \ + L"\0"; + break; + case FFLOAD_RAW: + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFLOAD_MODEL: + mOFN.lpstrFilter = MODEL_FILTER \ + L"\0"; + break; case FFLOAD_MATERIAL: mOFN.lpstrFilter = MATERIAL_FILTER \ L"\0"; @@ -229,74 +229,74 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) IMAGE_FILTER \ L"\0"; break; - case FFLOAD_SCRIPT: - mOFN.lpstrFilter = SCRIPT_FILTER \ - L"\0"; - break; - case FFLOAD_DICTIONARY: - mOFN.lpstrFilter = DICTIONARY_FILTER \ - L"\0"; - break; + case FFLOAD_SCRIPT: + mOFN.lpstrFilter = SCRIPT_FILTER \ + L"\0"; + break; + case FFLOAD_DICTIONARY: + mOFN.lpstrFilter = DICTIONARY_FILTER \ + L"\0"; + break; case FFLOAD_LUA: mOFN.lpstrFilter = LUA_FILTER \ L"\0"; break; - default: - res = FALSE; - break; - } - return res; + default: + res = FALSE; + break; + } + return res; } BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; - mOFN.nFilterIndex = 1; - - setupFilter(filter); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - reset(); - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - - if (blocking) - { - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - } - - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + mOFN.lpstrFile = mFilesW; + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; + mOFN.nFilterIndex = 1; + + setupFilter(filter); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + reset(); + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + + return success; } BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, @@ -310,79 +310,79 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nFilterIndex = 1; - mOFN.nMaxFile = FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | - OFN_EXPLORER | OFN_ALLOWMULTISELECT; - - setupFilter(filter); - - reset(); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); // pauses until ok or cancel. - if( success ) - { - // The getopenfilename api doesn't tell us if we got more than - // one file, so we have to test manually by checking string - // lengths. - if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - else - { - mLocked = true; - WCHAR* tptrw = mFilesW; - std::string dirname; - while(1) - { - if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' - break; - if (*tptrw == 0) - tptrw++; // shouldn't happen? - std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); - if (dirname.empty()) - dirname = filename + "\\"; - else - mFiles.push_back(dirname + filename); - tptrw += wcslen(tptrw); - } - } - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + mOFN.lpstrFile = mFilesW; + mOFN.nFilterIndex = 1; + mOFN.nMaxFile = FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | + OFN_EXPLORER | OFN_ALLOWMULTISELECT; + + setupFilter(filter); + + reset(); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); // pauses until ok or cancel. + if( success ) + { + // The getopenfilename api doesn't tell us if we got more than + // one file, so we have to test manually by checking string + // lengths. + if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + else + { + mLocked = true; + WCHAR* tptrw = mFilesW; + std::string dirname; + while(1) + { + if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' + break; + if (*tptrw == 0) + tptrw++; // shouldn't happen? + std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); + if (dirname.empty()) + dirname = filename + "\\"; + else + mFiles.push_back(dirname + filename); + tptrw += wcslen(tptrw); + } + } + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, @@ -396,222 +396,222 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - mOFN.lpstrFile = mFilesW; - if (!filename.empty()) - { - llutf16string tstring = utf8str_to_utf16str(filename); - wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ - else - { - mFilesW[0] = '\0'; - } - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - - switch( filter ) - { - case FFSAVE_ALL: - mOFN.lpstrDefExt = NULL; - mOFN.lpstrFilter = - L"All Files (*.*)\0*.*\0" \ - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ - L"\0"; - break; - case FFSAVE_WAV: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"wav"; - mOFN.lpstrFilter = - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"\0"; - break; - case FFSAVE_TGA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"tga"; - mOFN.lpstrFilter = - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - case FFSAVE_BMP: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"bmp"; - mOFN.lpstrFilter = - L"Bitmap Images (*.bmp)\0*.bmp\0" \ - L"\0"; - break; - case FFSAVE_PNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"\0"; - break; - case FFSAVE_TGAPNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - //PNG by default - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - - case FFSAVE_JPEG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"jpg"; - mOFN.lpstrFilter = - L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ - L"\0"; - break; - case FFSAVE_AVI: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"avi"; - mOFN.lpstrFilter = - L"AVI Movie File (*.avi)\0*.avi\0" \ - L"\0"; - break; - case FFSAVE_ANIM: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"xaf"; - mOFN.lpstrFilter = - L"XAF Anim File (*.xaf)\0*.xaf\0" \ - L"\0"; - break; - case FFSAVE_GLTF: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"glb"; - mOFN.lpstrFilter = - L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ - L"\0"; - break; - case FFSAVE_XML: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - - mOFN.lpstrDefExt = L"xml"; - mOFN.lpstrFilter = - L"XML File (*.xml)\0*.xml\0" \ - L"\0"; - break; - case FFSAVE_COLLADA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"collada"; - mOFN.lpstrFilter = - L"COLLADA File (*.collada)\0*.collada\0" \ - L"\0"; - break; - case FFSAVE_RAW: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"raw"; - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFSAVE_J2C: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"j2c"; - mOFN.lpstrFilter = - L"Compressed Images (*.j2c)\0*.j2c\0" \ - L"\0"; - break; - case FFSAVE_SCRIPT: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"txt"; - mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; - break; - default: - return FALSE; - } - - - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; - - reset(); - - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } - - { - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - try - { - success = GetSaveFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - } - catch (...) - { - LOG_UNHANDLED_EXCEPTION(""); - } - gKeyboard->resetKeys(); - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if( mLocked ) + { + return FALSE; + } + BOOL success = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + mOFN.lpstrFile = mFilesW; + if (!filename.empty()) + { + llutf16string tstring = utf8str_to_utf16str(filename); + wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ + else + { + mFilesW[0] = '\0'; + } + mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + + switch( filter ) + { + case FFSAVE_ALL: + mOFN.lpstrDefExt = NULL; + mOFN.lpstrFilter = + L"All Files (*.*)\0*.*\0" \ + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ + L"\0"; + break; + case FFSAVE_WAV: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"wav"; + mOFN.lpstrFilter = + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"\0"; + break; + case FFSAVE_TGA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"tga"; + mOFN.lpstrFilter = + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + case FFSAVE_BMP: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"bmp"; + mOFN.lpstrFilter = + L"Bitmap Images (*.bmp)\0*.bmp\0" \ + L"\0"; + break; + case FFSAVE_PNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"\0"; + break; + case FFSAVE_TGAPNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + //PNG by default + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + + case FFSAVE_JPEG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"jpg"; + mOFN.lpstrFilter = + L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ + L"\0"; + break; + case FFSAVE_AVI: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"avi"; + mOFN.lpstrFilter = + L"AVI Movie File (*.avi)\0*.avi\0" \ + L"\0"; + break; + case FFSAVE_ANIM: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"xaf"; + mOFN.lpstrFilter = + L"XAF Anim File (*.xaf)\0*.xaf\0" \ + L"\0"; + break; + case FFSAVE_GLTF: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"glb"; + mOFN.lpstrFilter = + L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ + L"\0"; + break; + case FFSAVE_XML: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + + mOFN.lpstrDefExt = L"xml"; + mOFN.lpstrFilter = + L"XML File (*.xml)\0*.xml\0" \ + L"\0"; + break; + case FFSAVE_COLLADA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"collada"; + mOFN.lpstrFilter = + L"COLLADA File (*.collada)\0*.collada\0" \ + L"\0"; + break; + case FFSAVE_RAW: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"raw"; + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFSAVE_J2C: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"j2c"; + mOFN.lpstrFilter = + L"Compressed Images (*.j2c)\0*.j2c\0" \ + L"\0"; + break; + case FFSAVE_SCRIPT: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"txt"; + mOFN.lpstrFilter = L"LSL Files (*.lsl)\0*.lsl\0" L"\0"; + break; + default: + return FALSE; + } + + + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; + + reset(); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + + { + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + try + { + success = GetSaveFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(""); + } + gKeyboard->resetKeys(); + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -690,25 +690,25 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF LL_WARNS() << "Unsupported format." << LL_ENDL; } - return allowedv; + return allowedv; } -bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) +bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) { - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return false; - } - - gViewerWindow->getWindow()->beforeDialog(); - + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } + + gViewerWindow->getWindow()->beforeDialog(); + std::unique_ptr> allowed_types = navOpenFilterProc(filter); - + std::unique_ptr> filev = doLoadDialog(allowed_types.get(), mPickOptions); - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); if (filev && filev->size() > 0) @@ -716,8 +716,8 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) mFiles.insert(mFiles.end(), filev->begin(), filev->end()); return true; } - - return false; + + return false; } bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, @@ -729,14 +729,14 @@ bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, { return false; } - + std::unique_ptr> allowed_types=navOpenFilterProc(filter); - + doLoadDialogModeless(allowed_types.get(), mPickOptions, callback, userdata); - + return true; } @@ -790,13 +790,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "\?\?\?\?"; extension = "glb"; break; - + case LLFilePicker::FFSAVE_XML: type = "\?\?\?\?"; creator = "\?\?\?\?"; extension = "xml"; break; - + case LLFilePicker::FFSAVE_RAW: type = "\?\?\?\?"; creator = "\?\?\?\?"; @@ -808,13 +808,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "prvw"; extension = "j2c"; break; - + case LLFilePicker::FFSAVE_SCRIPT: type = "LSL "; creator = "\?\?\?\?"; extension = "lsl"; break; - + case LLFilePicker::FFSAVE_ALL: default: type = "\?\?\?\?"; @@ -824,34 +824,34 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, } } -bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) { - // Setup the type, creator, and extension - std::string extension, type, creator; - + // Setup the type, creator, and extension + std::string extension, type, creator; + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; - - gViewerWindow->getWindow()->beforeDialog(); - // Run the dialog - std::unique_ptr filev = doSaveDialog(&namestring, + gViewerWindow->getWindow()->beforeDialog(); + + // Run the dialog + std::unique_ptr filev = doSaveDialog(&namestring, &type, &creator, &extension, mPickOptions); - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); - if ( filev && !filev->empty() ) - { + if ( filev && !filev->empty() ) + { mFiles.push_back(*filev); - return true; + return true; } - - return false; + + return false; } bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, @@ -861,9 +861,9 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; @@ -880,57 +880,57 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; + if( mLocked ) + return FALSE; - BOOL success = FALSE; + BOOL success = FALSE; - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); - reset(); - mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - - if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. + + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY ); mPickOptions &= ~F_FILE; } - if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful - { + if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful + { mPickOptions |= F_NAV_SUPPORT; - } - - if (blocking) // always true for linux/mac - { - // Modal, so pause agent - send_agent_pause(); - } - - - success = doNavChooseDialog(filter); - - if (success) - { - if (!getFileCount()) - success = false; - } - - if (blocking) - { - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - } - - return success; + } + + if (blocking) // always true for linux/mac + { + // Modal, so pause agent + send_agent_pause(); + } + + + success = doNavChooseDialog(filter); + + if (success) + { + if (!getFileCount()) + success = false; + } + + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + + return success; } @@ -948,10 +948,10 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { @@ -969,47 +969,47 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { - if( mLocked ) - return FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - + if( mLocked ) + return FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + BOOL success = FALSE; - reset(); - + reset(); + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; - if (blocking) // always true for linux/mac - { - // Modal, so pause agent - send_agent_pause(); - } - - success = doNavChooseDialog(filter); - - if (blocking) - { - send_agent_resume(); - } - - if (success) - { - if (!getFileCount()) - success = false; - if (getFileCount() > 1) - mLocked = true; - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + if (blocking) // always true for linux/mac + { + // Modal, so pause agent + send_agent_pause(); + } + + success = doNavChooseDialog(filter); + + if (blocking) + { + send_agent_resume(); + } + + if (success) + { + if (!getFileCount()) + success = false; + if (getFileCount() > 1) + mLocked = true; + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } @@ -1027,7 +1027,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, } reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1038,42 +1038,42 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { - if( mLocked ) - return false; - BOOL success = false; + if( mLocked ) + return false; + BOOL success = false; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return false; - } + reset(); - reset(); - mPickOptions &= ~F_MULTIPLE; - if (blocking) - { - // Modal, so pause agent - send_agent_pause(); - } + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } success = doNavSaveDialog(filter, filename); if (success) - { - if (!getFileCount()) - success = false; - } - - if (blocking) - { - send_agent_resume(); - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; + { + if (!getFileCount()) + success = false; + } + + if (blocking) + { + send_agent_resume(); + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -1083,7 +1083,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, { if( mLocked ) return false; - + // if local file browsing is turned off, return without opening dialog if ( check_local_file_access_enabled() == false ) { @@ -1091,7 +1091,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; return doNavSaveDialogModeless(filter, filename, callback, userdata); @@ -1105,414 +1105,414 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, // static void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) { - // We need to run g_filename_to_utf8 in the user's locale - std::string saved_locale(setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, ""); - - LLFilePicker* picker = (LLFilePicker*) user_data; - GError *error = NULL; - gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, - -1, NULL, NULL, &error); - if (error) - { - // *FIXME. - // This condition should really be notified to the user, e.g. - // through a message box. Just logging it is inappropriate. - - // g_filename_display_name is ideal, but >= glib 2.6, so: - // a hand-rolled hacky makeASCII which disallows control chars - std::string display_name; - for (const gchar *str = (const gchar *)data; *str; str++) - { - display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); - } - LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; - } - - if (filename_utf8) - { - picker->mFiles.push_back(std::string(filename_utf8)); - LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; - g_free(filename_utf8); - } - - setlocale(LC_ALL, saved_locale.c_str()); + // We need to run g_filename_to_utf8 in the user's locale + std::string saved_locale(setlocale(LC_ALL, NULL)); + setlocale(LC_ALL, ""); + + LLFilePicker* picker = (LLFilePicker*) user_data; + GError *error = NULL; + gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, + -1, NULL, NULL, &error); + if (error) + { + // *FIXME. + // This condition should really be notified to the user, e.g. + // through a message box. Just logging it is inappropriate. + + // g_filename_display_name is ideal, but >= glib 2.6, so: + // a hand-rolled hacky makeASCII which disallows control chars + std::string display_name; + for (const gchar *str = (const gchar *)data; *str; str++) + { + display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); + } + LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; + } + + if (filename_utf8) + { + picker->mFiles.push_back(std::string(filename_utf8)); + LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; + g_free(filename_utf8); + } + + setlocale(LC_ALL, saved_locale.c_str()); } // static void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) { - LLFilePicker* picker = (LLFilePicker*)user_data; - - LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); - g_slist_foreach(file_list, (GFunc)g_free, NULL); - g_slist_free (file_list); - } - - // let's save the extension of the last added file(considering current filter) - GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); - if(gfilter) - { - std::string filter = gtk_file_filter_get_name(gfilter); - - if(filter == LLTrans::getString("png_image_files")) - { - picker->mCurrentExtension = ".png"; - } - else if(filter == LLTrans::getString("targa_image_files")) - { - picker->mCurrentExtension = ".tga"; - } - } - - // set the default path for this usage context. - const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); - if (cur_folder != NULL) - { - picker->mContextToPathMap[picker->mCurContextName] = cur_folder; - } - - gtk_widget_destroy(widget); - gtk_main_quit(); + LLFilePicker* picker = (LLFilePicker*)user_data; + + LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; + + if (response == GTK_RESPONSE_ACCEPT) + { + GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); + g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); + g_slist_foreach(file_list, (GFunc)g_free, NULL); + g_slist_free (file_list); + } + + // let's save the extension of the last added file(considering current filter) + GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); + if(gfilter) + { + std::string filter = gtk_file_filter_get_name(gfilter); + + if(filter == LLTrans::getString("png_image_files")) + { + picker->mCurrentExtension = ".png"; + } + else if(filter == LLTrans::getString("targa_image_files")) + { + picker->mCurrentExtension = ".tga"; + } + } + + // set the default path for this usage context. + const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); + if (cur_folder != NULL) + { + picker->mContextToPathMap[picker->mCurContextName] = cur_folder; + } + + gtk_widget_destroy(widget); + gtk_main_quit(); } GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) { #ifndef LL_MESA_HEADLESS - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - GtkFileChooserAction pickertype = - is_save? - (is_folder? - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : - GTK_FILE_CHOOSER_ACTION_SAVE) : - (is_folder? - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : - GTK_FILE_CHOOSER_ACTION_OPEN); - - win = gtk_file_chooser_dialog_new(NULL, NULL, - pickertype, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - is_folder ? - GTK_STOCK_APPLY : - (is_save ? - GTK_STOCK_SAVE : - GTK_STOCK_OPEN), - GTK_RESPONSE_ACCEPT, - (gchar *)NULL); - mCurContextName = context; - - // get the default path for this usage context if it's been - // seen before. - std::map::iterator - this_path = mContextToPathMap.find(context); - if (this_path != mContextToPathMap.end()) - { - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(win), - this_path->second.c_str()); - } + if (LLWindowSDL::ll_try_gtk_init()) + { + GtkWidget *win = NULL; + GtkFileChooserAction pickertype = + is_save? + (is_folder? + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : + GTK_FILE_CHOOSER_ACTION_SAVE) : + (is_folder? + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : + GTK_FILE_CHOOSER_ACTION_OPEN); + + win = gtk_file_chooser_dialog_new(NULL, NULL, + pickertype, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + is_folder ? + GTK_STOCK_APPLY : + (is_save ? + GTK_STOCK_SAVE : + GTK_STOCK_OPEN), + GTK_RESPONSE_ACCEPT, + (gchar *)NULL); + mCurContextName = context; + + // get the default path for this usage context if it's been + // seen before. + std::map::iterator + this_path = mContextToPathMap.find(context); + if (this_path != mContextToPathMap.end()) + { + gtk_file_chooser_set_current_folder + (GTK_FILE_CHOOSER(win), + this_path->second.c_str()); + } # if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK raw X11 window, which should try - // to keep it on top etc. - Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); - if (None != XWindowID) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } - else - { - LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; - } + // Make GTK tell the window manager to associate this + // dialog with our non-GTK raw X11 window, which should try + // to keep it on top etc. + Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); + if (None != XWindowID) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, + gdkwin); + } + else + { + LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; + } # endif //LL_X11 - g_signal_connect (GTK_FILE_CHOOSER(win), - "response", - G_CALLBACK(LLFilePicker::chooser_responder), - this); + g_signal_connect (GTK_FILE_CHOOSER(win), + "response", + G_CALLBACK(LLFilePicker::chooser_responder), + this); - gtk_window_set_modal(GTK_WINDOW(win), TRUE); + gtk_window_set_modal(GTK_WINDOW(win), TRUE); - /* GTK 2.6: if (is_folder) - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), - TRUE); */ + /* GTK 2.6: if (is_folder) + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), + TRUE); */ - return GTK_WINDOW(win); - } - else - { - return NULL; - } + return GTK_WINDOW(win); + } + else + { + return NULL; + } #else - return NULL; + return NULL; #endif //LL_MESA_HEADLESS } static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, - GtkWindow *picker, - std::string filtername) -{ - gtk_file_filter_set_name(gfilter, filtername.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter); - GtkFileFilter *allfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(allfilter, "*"); - gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); + GtkWindow *picker, + std::string filtername) +{ + gtk_file_filter_set_name(gfilter, filtername.c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter); + GtkFileFilter *allfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(allfilter, "*"); + gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); } static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, - std::string pattern, - std::string filtername) + std::string pattern, + std::string filtername) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, pattern.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, pattern.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, - std::string mime, - std::string filtername) + std::string mime, + std::string filtername) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_mime_type(gfilter, mime.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_mime_type(gfilter, mime.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", - LLTrans::getString("sound_files") + " (*.wav)"); + return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", + LLTrans::getString("sound_files") + " (*.wav)"); } static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.bvh"); - gtk_file_filter_add_pattern(gfilter, "*.anim"); - std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.bvh"); + gtk_file_filter_add_pattern(gfilter, "*.anim"); + std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", - LLTrans::getString("xml_files") + " (*.xml)"); + return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", + LLTrans::getString("xml_files") + " (*.xml)"); } static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", - LLTrans::getString("scene_files") + " (*.dae)"); + return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", + LLTrans::getString("scene_files") + " (*.dae)"); } static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); - gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.tga"); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); + gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); + std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; } - + static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("script_files") + " (*.lsl)"); + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, + LLTrans::getString("script_files") + " (*.lsl)"); } static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) { - return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, - LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); + return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, + LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); } static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter_tga = gtk_file_filter_new(); - GtkFileFilter *gfilter_png = gtk_file_filter_new(); - - gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); - gtk_file_filter_add_mime_type(gfilter_png, "image/png"); - std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; - gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); - gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); - - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_png); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter_tga); - return caption; + GtkFileFilter *gfilter_tga = gtk_file_filter_new(); + GtkFileFilter *gfilter_png = gtk_file_filter_new(); + + gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); + gtk_file_filter_add_mime_type(gfilter_png, "image/png"); + std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; + gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); + gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); + + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter_png); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter_tga); + return caption; } BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(true, false, "savefile"); - - if (picker) - { - std::string suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) - { - case FFSAVE_WAV: - caption += add_wav_filter_to_gtkchooser(picker); - suggest_ext = ".wav"; - break; - case FFSAVE_TGA: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); - suggest_ext = ".tga"; - break; - case FFSAVE_BMP: - caption += add_simple_mime_filter_to_gtkchooser - (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); - suggest_ext = ".bmp"; - break; - case FFSAVE_PNG: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); - suggest_ext = ".png"; - break; - case FFSAVE_TGAPNG: - caption += add_save_texture_filter_to_gtkchooser(picker); - suggest_ext = ".png"; - break; - case FFSAVE_AVI: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "video/x-msvideo", - LLTrans::getString("avi_movie_file") + " (*.avi)"); - suggest_ext = ".avi"; - break; - case FFSAVE_ANIM: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); - suggest_ext = ".xaf"; - break; - case FFSAVE_XML: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); - suggest_ext = ".xml"; - break; - case FFSAVE_RAW: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); - suggest_ext = ".raw"; - break; - case FFSAVE_J2C: - // *TODO: Should this be 'image/j2c' ? - caption += add_simple_mime_filter_to_gtkchooser - (picker, "images/jp2", - LLTrans::getString("compressed_image_files") + " (*.j2c)"); - suggest_ext = ".j2c"; - break; - case FFSAVE_SCRIPT: - caption += add_script_filter_to_gtkchooser(picker); - suggest_ext = ".lsl"; - break; - default:; - break; - } - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - if (filename.empty()) - { - suggest_name += suggest_ext; - - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), - suggest_name.c_str()); - } - else - { - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), filename.c_str()); - } - - gtk_widget_show_all(GTK_WIDGET(picker)); - - gtk_main(); - - rtn = (getFileCount() == 1); - - if(rtn && filter == FFSAVE_TGAPNG) - { - std::string selected_file = mFiles.back(); - mFiles.pop_back(); - mFiles.push_back(selected_file + mCurrentExtension); - } - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + gViewerWindow->getWindow()->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(true, false, "savefile"); + + if (picker) + { + std::string suggest_name = "untitled"; + std::string suggest_ext = ""; + std::string caption = LLTrans::getString("save_file_verb") + " "; + switch (filter) + { + case FFSAVE_WAV: + caption += add_wav_filter_to_gtkchooser(picker); + suggest_ext = ".wav"; + break; + case FFSAVE_TGA: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); + suggest_ext = ".tga"; + break; + case FFSAVE_BMP: + caption += add_simple_mime_filter_to_gtkchooser + (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); + suggest_ext = ".bmp"; + break; + case FFSAVE_PNG: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); + suggest_ext = ".png"; + break; + case FFSAVE_TGAPNG: + caption += add_save_texture_filter_to_gtkchooser(picker); + suggest_ext = ".png"; + break; + case FFSAVE_AVI: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "video/x-msvideo", + LLTrans::getString("avi_movie_file") + " (*.avi)"); + suggest_ext = ".avi"; + break; + case FFSAVE_ANIM: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); + suggest_ext = ".xaf"; + break; + case FFSAVE_XML: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); + suggest_ext = ".xml"; + break; + case FFSAVE_RAW: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); + suggest_ext = ".raw"; + break; + case FFSAVE_J2C: + // *TODO: Should this be 'image/j2c' ? + caption += add_simple_mime_filter_to_gtkchooser + (picker, "images/jp2", + LLTrans::getString("compressed_image_files") + " (*.j2c)"); + suggest_ext = ".j2c"; + break; + case FFSAVE_SCRIPT: + caption += add_script_filter_to_gtkchooser(picker); + suggest_ext = ".lsl"; + break; + default:; + break; + } + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + if (filename.empty()) + { + suggest_name += suggest_ext; + + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), + suggest_name.c_str()); + } + else + { + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), filename.c_str()); + } + + gtk_widget_show_all(GTK_WIDGET(picker)); + + gtk_main(); + + rtn = (getFileCount() == 1); + + if(rtn && filter == FFSAVE_TGAPNG) + { + std::string selected_file = mFiles.back(); + mFiles.pop_back(); + mFiles.push_back(selected_file + mCurrentExtension); + } + } + + gViewerWindow->getWindow()->afterDialog(); + + return rtn; } BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - BOOL rtn = FALSE; - - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - std::string caption = LLTrans::getString("load_file_verb") + " "; - std::string filtername = ""; - switch (filter) - { - case FFLOAD_WAV: - filtername = add_wav_filter_to_gtkchooser(picker); - break; - case FFLOAD_ANIM: - filtername = add_anim_filter_to_gtkchooser(picker); - break; - case FFLOAD_XML: - filtername = add_xml_filter_to_gtkchooser(picker); - break; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + gViewerWindow->getWindow()->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(false, false, "openfile"); + + if (picker) + { + std::string caption = LLTrans::getString("load_file_verb") + " "; + std::string filtername = ""; + switch (filter) + { + case FFLOAD_WAV: + filtername = add_wav_filter_to_gtkchooser(picker); + break; + case FFLOAD_ANIM: + filtername = add_anim_filter_to_gtkchooser(picker); + break; + case FFLOAD_XML: + filtername = add_xml_filter_to_gtkchooser(picker); + break; case FFLOAD_GLTF: filtername = dead_code_should_blow_up_here(picker); break; @@ -1520,64 +1520,64 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) filtername = add_collada_filter_to_gtkchooser(picker); break; case FFLOAD_IMAGE: - filtername = add_imageload_filter_to_gtkchooser(picker); - break; - case FFLOAD_SCRIPT: - filtername = add_script_filter_to_gtkchooser(picker); - break; - case FFLOAD_DICTIONARY: - filtername = add_dictionary_filter_to_gtkchooser(picker); - break; - default:; - break; - } - - caption += filtername; - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); - } - - gViewerWindow->getWindow()->afterDialog(); - - return rtn; + filtername = add_imageload_filter_to_gtkchooser(picker); + break; + case FFLOAD_SCRIPT: + filtername = add_script_filter_to_gtkchooser(picker); + break; + case FFLOAD_DICTIONARY: + filtername = add_dictionary_filter_to_gtkchooser(picker); + break; + default:; + break; + } + + caption += filtername; + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + + rtn = (getFileCount() == 1); + } + + gViewerWindow->getWindow()->afterDialog(); + + return rtn; } BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - BOOL rtn = FALSE; + BOOL rtn = FALSE; + + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } - // if local file browsing is turned off, return without opening dialog - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } + gViewerWindow->getWindow()->beforeDialog(); - gViewerWindow->getWindow()->beforeDialog(); + reset(); - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); + GtkWindow* picker = buildFilePicker(false, false, "openfile"); - if (picker) - { - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), - TRUE); + if (picker) + { + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), + TRUE); - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); + gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - rtn = !mFiles.empty(); - } + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + rtn = !mFiles.empty(); + } - gViewerWindow->getWindow()->afterDialog(); + gViewerWindow->getWindow()->afterDialog(); - return rtn; + return rtn; } # else // LL_GTK @@ -1587,23 +1587,23 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - - LL_INFOS() << "getSaveFile suggested filename is [" << filename - << "]" << LL_ENDL; - if (!filename.empty()) - { - mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); - return TRUE; - } - return FALSE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + + LL_INFOS() << "getSaveFile suggested filename is [" << filename + << "]" << LL_ENDL; + if (!filename.empty()) + { + mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); + return TRUE; + } + return FALSE; } BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, @@ -1617,27 +1617,27 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - - // HACK: Static filenames for 'open' until we implement filepicker - std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; - switch (filter) - { - case FFLOAD_WAV: filename += ".wav"; break; - case FFLOAD_IMAGE: filename += ".tga"; break; - case FFLOAD_ANIM: filename += ".bvh"; break; - default: break; - } - mFiles.push_back(filename); - LL_INFOS() << "getOpenFile: Will try to open file: " << filename << LL_ENDL; - return TRUE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + + // HACK: Static filenames for 'open' until we implement filepicker + std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; + switch (filter) + { + case FFLOAD_WAV: filename += ".wav"; break; + case FFLOAD_IMAGE: filename += ".tga"; break; + case FFLOAD_ANIM: filename += ".bvh"; break; + default: break; + } + mFiles.push_back(filename); + LL_INFOS() << "getOpenFile: Will try to open file: " << filename << LL_ENDL; + return TRUE; } BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, @@ -1650,15 +1650,15 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - // if local file browsing is turned off, return without opening dialog - // (Even though this is a stub, I think we still should not return anything at all) - if ( check_local_file_access_enabled() == false ) - { - return FALSE; - } - - reset(); - return FALSE; + // if local file browsing is turned off, return without opening dialog + // (Even though this is a stub, I think we still should not return anything at all) + if ( check_local_file_access_enabled() == false ) + { + return FALSE; + } + + reset(); + return FALSE; } BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, @@ -1675,20 +1675,20 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) { - reset(); - return FALSE; + reset(); + return FALSE; } BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) { - reset(); - return FALSE; + reset(); + return FALSE; } BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { - reset(); - return FALSE; + reset(); + return FALSE; } #endif // LL_LINUX diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index f00f076d1c..c4380dcd19 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.h * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,119 +64,119 @@ extern "C" { class LLFilePicker { #ifdef LL_GTK - friend class LLDirPicker; - friend void chooser_responder(GtkWidget *, gint, gpointer); + friend class LLDirPicker; + friend void chooser_responder(GtkWidget *, gint, gpointer); #endif // LL_GTK public: - // calling this before main() is undefined - static LLFilePicker& instance( void ) { return sInstance; } - - enum ELoadFilter - { - FFLOAD_ALL = 1, - FFLOAD_WAV = 2, - FFLOAD_IMAGE = 3, - FFLOAD_ANIM = 4, - FFLOAD_GLTF = 5, - FFLOAD_XML = 6, - FFLOAD_SLOBJECT = 7, - FFLOAD_RAW = 8, - FFLOAD_MODEL = 9, - FFLOAD_COLLADA = 10, - FFLOAD_SCRIPT = 11, - FFLOAD_DICTIONARY = 12, + // calling this before main() is undefined + static LLFilePicker& instance( void ) { return sInstance; } + + enum ELoadFilter + { + FFLOAD_ALL = 1, + FFLOAD_WAV = 2, + FFLOAD_IMAGE = 3, + FFLOAD_ANIM = 4, + FFLOAD_GLTF = 5, + FFLOAD_XML = 6, + FFLOAD_SLOBJECT = 7, + FFLOAD_RAW = 8, + FFLOAD_MODEL = 9, + FFLOAD_COLLADA = 10, + FFLOAD_SCRIPT = 11, + FFLOAD_DICTIONARY = 12, FFLOAD_DIRECTORY = 13, // To call from lldirpicker. FFLOAD_EXE = 14, // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin FFLOAD_MATERIAL = 15, FFLOAD_MATERIAL_TEXTURE = 16, FFLOAD_LUA = 17, - }; - - enum ESaveFilter - { - FFSAVE_ALL = 1, - FFSAVE_WAV = 3, - FFSAVE_TGA = 4, - FFSAVE_BMP = 5, - FFSAVE_AVI = 6, - FFSAVE_ANIM = 7, - FFSAVE_GLTF = 8, - FFSAVE_XML = 9, - FFSAVE_COLLADA = 10, - FFSAVE_RAW = 11, - FFSAVE_J2C = 12, - FFSAVE_PNG = 13, - FFSAVE_JPEG = 14, - FFSAVE_SCRIPT = 15, - FFSAVE_TGAPNG = 16 - }; - - // open the dialog. This is a modal operation - BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); + }; + + enum ESaveFilter + { + FFSAVE_ALL = 1, + FFSAVE_WAV = 3, + FFSAVE_TGA = 4, + FFSAVE_BMP = 5, + FFSAVE_AVI = 6, + FFSAVE_ANIM = 7, + FFSAVE_GLTF = 8, + FFSAVE_XML = 9, + FFSAVE_COLLADA = 10, + FFSAVE_RAW = 11, + FFSAVE_J2C = 12, + FFSAVE_PNG = 13, + FFSAVE_JPEG = 14, + FFSAVE_SCRIPT = 15, + FFSAVE_TGAPNG = 16 + }; + + // open the dialog. This is a modal operation + BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); BOOL getSaveFileModeless(ESaveFilter filter, const std::string& filename, void (*callback)(bool, std::string&, void*), void *userdata); - BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); // Todo: implement getOpenFileModeless and getMultipleOpenFilesModeless // for windows and use directly instead of ugly LLFilePickerThread BOOL getOpenFileModeless( ELoadFilter filter, void (*callback)(bool, std::vector &, void*), void *userdata); // MAC only. - BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); BOOL getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector &, void*), void *userdata ); // MAC only - // Get the filename(s) found. getFirstFile() sets the pointer to - // the start of the structure and allows the start of iteration. - const std::string getFirstFile(); + // Get the filename(s) found. getFirstFile() sets the pointer to + // the start of the structure and allows the start of iteration. + const std::string getFirstFile(); + + // getNextFile() increments the internal representation and + // returns the next file specified by the user. Returns NULL when + // no more files are left. Further calls to getNextFile() are + // undefined. + const std::string getNextFile(); - // getNextFile() increments the internal representation and - // returns the next file specified by the user. Returns NULL when - // no more files are left. Further calls to getNextFile() are - // undefined. - const std::string getNextFile(); + // This utility function extracts the current file name without + // doing any incrementing. + const std::string getCurFile(); - // This utility function extracts the current file name without - // doing any incrementing. - const std::string getCurFile(); + // Returns the index of the current file. + S32 getCurFileNum() const { return mCurrentFile; } - // Returns the index of the current file. - S32 getCurFileNum() const { return mCurrentFile; } + S32 getFileCount() const { return (S32)mFiles.size(); } - S32 getFileCount() const { return (S32)mFiles.size(); } + // see lldir.h : getBaseFileName and getDirName to extract base or directory names - // see lldir.h : getBaseFileName and getDirName to extract base or directory names - - // clear any lists of buffers or whatever, and make sure the file - // picker isn't locked. - void reset(); + // clear any lists of buffers or whatever, and make sure the file + // picker isn't locked. + void reset(); private: - enum - { - SINGLE_FILENAME_BUFFER_SIZE = 1024, - //FILENAME_BUFFER_SIZE = 65536 - FILENAME_BUFFER_SIZE = 65000 - }; - - // utility function to check if access to local file system via file browser - // is enabled and if not, tidy up and indicate we're not allowed to do this. - bool check_local_file_access_enabled(); - + enum + { + SINGLE_FILENAME_BUFFER_SIZE = 1024, + //FILENAME_BUFFER_SIZE = 65536 + FILENAME_BUFFER_SIZE = 65000 + }; + + // utility function to check if access to local file system via file browser + // is enabled and if not, tidy up and indicate we're not allowed to do this. + bool check_local_file_access_enabled(); + #if LL_WINDOWS - OPENFILENAMEW mOFN; // for open and save dialogs - WCHAR mFilesW[FILENAME_BUFFER_SIZE]; + OPENFILENAMEW mOFN; // for open and save dialogs + WCHAR mFilesW[FILENAME_BUFFER_SIZE]; - BOOL setupFilter(ELoadFilter filter); + BOOL setupFilter(ELoadFilter filter); #endif #if LL_DARWIN S32 mPickOptions; - std::vector mFileVector; - - bool doNavChooseDialog(ELoadFilter filter); - bool doNavChooseDialogModeless(ELoadFilter filter, + std::vector mFileVector; + + bool doNavChooseDialog(ELoadFilter filter); + bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector&, void*), void *userdata); - bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); + bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); std::unique_ptr> navOpenFilterProc(ELoadFilter filter); bool doNavSaveDialogModeless(ESaveFilter filter, const std::string& filename, @@ -185,31 +185,31 @@ private: #endif #if LL_GTK - static void add_to_selectedfiles(gpointer data, gpointer user_data); - static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); - // we remember the last path that was accessed for a particular usage - std::map mContextToPathMap; - std::string mCurContextName; - // we also remember the extension of the last added file. - std::string mCurrentExtension; + static void add_to_selectedfiles(gpointer data, gpointer user_data); + static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); + // we remember the last path that was accessed for a particular usage + std::map mContextToPathMap; + std::string mCurContextName; + // we also remember the extension of the last added file. + std::string mCurrentExtension; #endif - std::vector mFiles; - S32 mCurrentFile; - bool mLocked; + std::vector mFiles; + S32 mCurrentFile; + bool mLocked; + + static LLFilePicker sInstance; - static LLFilePicker sInstance; - protected: #if LL_GTK GtkWindow* buildFilePicker(bool is_save, bool is_folder, - std::string context = "generic"); + std::string context = "generic"); #endif public: - // don't call these directly please. - LLFilePicker(); - ~LLFilePicker(); + // don't call these directly please. + LLFilePicker(); + ~LLFilePicker(); }; #endif diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 0bc3c241fa..956ab0d7bc 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2017&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2017, 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$ */ @@ -38,14 +38,14 @@ #include "llviewercontrol.h" LLFloaterLinkReplace::LLFloaterLinkReplace(const LLSD& key) - : LLFloater(key), - LLEventTimer(gSavedSettings.getF32("LinkReplaceBatchPauseTime")), - mRemainingItems(0), - mSourceUUID(LLUUID::null), - mTargetUUID(LLUUID::null), - mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize")) + : LLFloater(key), + LLEventTimer(gSavedSettings.getF32("LinkReplaceBatchPauseTime")), + mRemainingItems(0), + mSourceUUID(LLUUID::null), + mTargetUUID(LLUUID::null), + mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize")) { - stop(); + stop(); } LLFloaterLinkReplace::~LLFloaterLinkReplace() @@ -54,322 +54,322 @@ LLFloaterLinkReplace::~LLFloaterLinkReplace() BOOL LLFloaterLinkReplace::postBuild() { - mStartBtn = getChild("btn_start"); - mStartBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::onStartClicked, this)); + mStartBtn = getChild("btn_start"); + mStartBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::onStartClicked, this)); - mRefreshBtn = getChild("btn_refresh"); - mRefreshBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::checkEnableStart, this)); + mRefreshBtn = getChild("btn_refresh"); + mRefreshBtn->setCommitCallback(boost::bind(&LLFloaterLinkReplace::checkEnableStart, this)); - mSourceEditor = getChild("source_uuid_editor"); - mTargetEditor = getChild("target_uuid_editor"); + mSourceEditor = getChild("source_uuid_editor"); + mTargetEditor = getChild("target_uuid_editor"); - mSourceEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onSourceItemDrop, this, _1)); - mTargetEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onTargetItemDrop, this, _1)); + mSourceEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onSourceItemDrop, this, _1)); + mTargetEditor->setDADCallback(boost::bind(&LLFloaterLinkReplace::onTargetItemDrop, this, _1)); - mStatusText = getChild("status_text"); + mStatusText = getChild("status_text"); - return TRUE; + return TRUE; } void LLFloaterLinkReplace::onOpen(const LLSD& key) { - if (key.asUUID().notNull()) - { - LLUUID item_id = key.asUUID(); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - mSourceEditor->setItem(item); - onSourceItemDrop(item->getLinkedUUID()); - } - else - { - checkEnableStart(); - } + if (key.asUUID().notNull()) + { + LLUUID item_id = key.asUUID(); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + mSourceEditor->setItem(item); + onSourceItemDrop(item->getLinkedUUID()); + } + else + { + checkEnableStart(); + } } void LLFloaterLinkReplace::onSourceItemDrop(const LLUUID& source_item_id) { - mSourceUUID = source_item_id; - checkEnableStart(); + mSourceUUID = source_item_id; + checkEnableStart(); } void LLFloaterLinkReplace::onTargetItemDrop(const LLUUID& target_item_id) { - mTargetUUID = target_item_id; - checkEnableStart(); + mTargetUUID = target_item_id; + checkEnableStart(); } void LLFloaterLinkReplace::updateFoundLinks() { - LLInventoryModel::item_array_t items; - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - items, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - mRemainingItems = (U32)items.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsFound", args)); + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + items, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + mRemainingItems = (U32)items.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsFound", args)); } void LLFloaterLinkReplace::checkEnableStart() { - if (mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID == mTargetUUID) - { - mStatusText->setText(getString("ItemsIdentical")); - } - else if (mSourceUUID.notNull()) - { - updateFoundLinks(); - } - - mStartBtn->setEnabled(mRemainingItems > 0 && mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID != mTargetUUID); + if (mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID == mTargetUUID) + { + mStatusText->setText(getString("ItemsIdentical")); + } + else if (mSourceUUID.notNull()) + { + updateFoundLinks(); + } + + mStartBtn->setEnabled(mRemainingItems > 0 && mSourceUUID.notNull() && mTargetUUID.notNull() && mSourceUUID != mTargetUUID); } void LLFloaterLinkReplace::onStartClicked() { - LL_INFOS() << "Starting inventory link replace" << LL_ENDL; - - if (mSourceUUID.isNull() || mTargetUUID.isNull()) - { - LL_WARNS() << "Cannot replace. Either source or target UUID is null." << LL_ENDL; - return; - } - - if (mSourceUUID == mTargetUUID) - { - LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; - return; - } - - const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); - LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); - const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); - LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); - - - LLNotification::Params params("ConfirmReplaceLink"); - params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); - if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) - { - if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) - { - LLNotifications::instance().forceResponse(params, 0); - } - else - { - LLSD args; - args["TYPE"] = LLWearableType::getInstance()->getTypeName(source_item->getWearableType()); - params.substitutions(args); - LLNotifications::instance().add(params); - } - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } + LL_INFOS() << "Starting inventory link replace" << LL_ENDL; + + if (mSourceUUID.isNull() || mTargetUUID.isNull()) + { + LL_WARNS() << "Cannot replace. Either source or target UUID is null." << LL_ENDL; + return; + } + + if (mSourceUUID == mTargetUUID) + { + LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; + return; + } + + const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); + LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); + const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); + LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); + + + LLNotification::Params params("ConfirmReplaceLink"); + params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); + if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) + { + if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) + { + LLNotifications::instance().forceResponse(params, 0); + } + else + { + LLSD args; + args["TYPE"] = LLWearableType::getInstance()->getTypeName(source_item->getWearableType()); + params.substitutions(args); + LLNotifications::instance().add(params); + } + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } } void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, const LLSD& response) { - if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) - { - - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - mRemainingInventoryItems, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; - - if (mRemainingInventoryItems.size() > 0) - { - LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - if (target_item) - { - mRemainingItems = (U32)mRemainingInventoryItems.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - - mStartBtn->setEnabled(FALSE); - mRefreshBtn->setEnabled(FALSE); - - start(); - tick(); - } - else - { - mStatusText->setText(getString("TargetNotFound")); - LL_WARNS() << "Link replace target not found." << LL_ENDL; - } - } - } + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + mRemainingInventoryItems, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; + + if (mRemainingInventoryItems.size() > 0) + { + LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + if (target_item) + { + mRemainingItems = (U32)mRemainingInventoryItems.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + + mStartBtn->setEnabled(FALSE); + mRefreshBtn->setEnabled(FALSE); + + start(); + tick(); + } + else + { + mStatusText->setText(getString("TargetNotFound")); + LL_WARNS() << "Link replace target not found." << LL_ENDL; + } + } + } } // static void LLFloaterLinkReplace::linkCreatedCallback(LLHandle floater_handle, const LLUUID& old_item_id, const LLUUID& target_item_id, - bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id) + bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id) { - LL_DEBUGS() << "Inventory link replace:" << LL_NEWLINE - << " - old_item_id = " << old_item_id.asString() << LL_NEWLINE - << " - target_item_id = " << target_item_id.asString() << LL_NEWLINE - << " - order update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE - << " - description update = " << (needs_description_update ? "true" : "false") << LL_NEWLINE - << " - outfit_folder_id = " << outfit_folder_id.asString() << LL_ENDL; - - // If we are replacing an object, bodypart or gesture link within an outfit folder, - // we need to change the actual description of the link itself. LLAppearanceMgr *should* - // have created COF links that will be used to save the outfit with an empty description. - // Since link_inventory_array() will set the description of the linked item for the link - // itself, this will lead to a dirty outfit state when the outfit with the replaced - // link is worn. So we have to correct this. - if (needs_description_update && outfit_folder_id.notNull()) - { - LLInventoryModel::item_array_t items; - LLInventoryModel::cat_array_t cats; - LLLinkedItemIDMatches is_target_link(target_item_id); - gInventory.collectDescendentsIf(outfit_folder_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_target_link); - - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - LLPointer item = *it; - - if ((item->getType() == LLAssetType::AT_BODYPART || - item->getType() == LLAssetType::AT_OBJECT || - item->getType() == LLAssetType::AT_GESTURE) - && !item->getActualDescription().empty()) - { - LL_DEBUGS() << "Updating description for " << item->getName() << LL_ENDL; - - LLSD updates; - updates["desc"] = ""; - update_inventory_item(item->getUUID(), updates, LLPointer(NULL)); - } - } - } - - LLUUID outfit_update_folder = LLUUID::null; - if (needs_wearable_ordering_update && outfit_folder_id.notNull()) - { - // If a wearable item was involved in the link replace operation and replaced - // a link in an outfit folder, we need to update the clothing ordering information - // *after* the original link has been removed. LLAppearanceMgr abuses the actual link - // description to store the clothing ordering information it. We will have to update - // the clothing ordering information or the outfit will be in dirty state when worn. - outfit_update_folder = outfit_folder_id; - } - - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::itemRemovedCallback, floater_handle, outfit_update_folder)); - remove_inventory_object(old_item_id, cb); + LL_DEBUGS() << "Inventory link replace:" << LL_NEWLINE + << " - old_item_id = " << old_item_id.asString() << LL_NEWLINE + << " - target_item_id = " << target_item_id.asString() << LL_NEWLINE + << " - order update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE + << " - description update = " << (needs_description_update ? "true" : "false") << LL_NEWLINE + << " - outfit_folder_id = " << outfit_folder_id.asString() << LL_ENDL; + + // If we are replacing an object, bodypart or gesture link within an outfit folder, + // we need to change the actual description of the link itself. LLAppearanceMgr *should* + // have created COF links that will be used to save the outfit with an empty description. + // Since link_inventory_array() will set the description of the linked item for the link + // itself, this will lead to a dirty outfit state when the outfit with the replaced + // link is worn. So we have to correct this. + if (needs_description_update && outfit_folder_id.notNull()) + { + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + LLLinkedItemIDMatches is_target_link(target_item_id); + gInventory.collectDescendentsIf(outfit_folder_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_target_link); + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + LLPointer item = *it; + + if ((item->getType() == LLAssetType::AT_BODYPART || + item->getType() == LLAssetType::AT_OBJECT || + item->getType() == LLAssetType::AT_GESTURE) + && !item->getActualDescription().empty()) + { + LL_DEBUGS() << "Updating description for " << item->getName() << LL_ENDL; + + LLSD updates; + updates["desc"] = ""; + update_inventory_item(item->getUUID(), updates, LLPointer(NULL)); + } + } + } + + LLUUID outfit_update_folder = LLUUID::null; + if (needs_wearable_ordering_update && outfit_folder_id.notNull()) + { + // If a wearable item was involved in the link replace operation and replaced + // a link in an outfit folder, we need to update the clothing ordering information + // *after* the original link has been removed. LLAppearanceMgr abuses the actual link + // description to store the clothing ordering information it. We will have to update + // the clothing ordering information or the outfit will be in dirty state when worn. + outfit_update_folder = outfit_folder_id; + } + + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::itemRemovedCallback, floater_handle, outfit_update_folder)); + remove_inventory_object(old_item_id, cb); } // static void LLFloaterLinkReplace::itemRemovedCallback(LLHandle floater_handle, const LLUUID& outfit_folder_id) { - if (outfit_folder_id.notNull()) - { - LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(outfit_folder_id); - } - - if (!floater_handle.isDead()) - { - floater_handle.get()->decreaseOpenItemCount(); - } + if (outfit_folder_id.notNull()) + { + LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(outfit_folder_id); + } + + if (!floater_handle.isDead()) + { + floater_handle.get()->decreaseOpenItemCount(); + } } void LLFloaterLinkReplace::decreaseOpenItemCount() { - mRemainingItems--; - - if (mRemainingItems == 0) - { - mStatusText->setText(getString("ReplaceFinished")); - mStartBtn->setEnabled(TRUE); - mRefreshBtn->setEnabled(TRUE); - stop(); - LL_INFOS() << "Inventory link replace finished." << LL_ENDL; - } - else - { - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - LL_DEBUGS() << "Inventory link replace: " << mRemainingItems << " links remaining..." << LL_ENDL; - } + mRemainingItems--; + + if (mRemainingItems == 0) + { + mStatusText->setText(getString("ReplaceFinished")); + mStartBtn->setEnabled(TRUE); + mRefreshBtn->setEnabled(TRUE); + stop(); + LL_INFOS() << "Inventory link replace finished." << LL_ENDL; + } + else + { + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + LL_DEBUGS() << "Inventory link replace: " << mRemainingItems << " links remaining..." << LL_ENDL; + } } bool LLFloaterLinkReplace::tick() { - LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; + LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; - LLInventoryModel::item_array_t current_batch; + LLInventoryModel::item_array_t current_batch; - for (U32 i = 0; i < mBatchSize; ++i) - { - if (!mRemainingInventoryItems.size()) - { - stop(); - break; - } + for (U32 i = 0; i < mBatchSize; ++i) + { + if (!mRemainingInventoryItems.size()) + { + stop(); + break; + } - current_batch.push_back(mRemainingInventoryItems.back()); - mRemainingInventoryItems.pop_back(); - } - processBatch(current_batch); + current_batch.push_back(mRemainingInventoryItems.back()); + mRemainingInventoryItems.pop_back(); + } + processBatch(current_batch); - return FALSE; + return FALSE; } void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) { - const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - LLPointer source_item = *it; - - if (source_item->getParentUUID() != cof_folder_id) - { - bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); - // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced - bool needs_wearable_ordering_update = (is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING) || target_item->getType() == LLAssetType::AT_CLOTHING; - // Other items in the COF need a description update (description of the actual link item must be empty) - bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; - - LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE - << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE - << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; - - LLInventoryObject::const_object_list_t obj_array; - obj_array.push_back(LLConstPointer(target_item)); - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::linkCreatedCallback, - getDerivedHandle(), - source_item->getUUID(), - target_item->getUUID(), - needs_wearable_ordering_update, - needs_description_update, - (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) )); - link_inventory_array(source_item->getParentUUID(), obj_array, cb); - } - else - { - decreaseOpenItemCount(); - } - } + const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + LLPointer source_item = *it; + + if (source_item->getParentUUID() != cof_folder_id) + { + bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); + // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced + bool needs_wearable_ordering_update = (is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING) || target_item->getType() == LLAssetType::AT_CLOTHING; + // Other items in the COF need a description update (description of the actual link item must be empty) + bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; + + LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE + << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE + << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; + + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(LLConstPointer(target_item)); + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&LLFloaterLinkReplace::linkCreatedCallback, + getDerivedHandle(), + source_item->getUUID(), + target_item->getUUID(), + needs_wearable_ordering_update, + needs_description_update, + (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) )); + link_inventory_array(source_item->getParentUUID(), obj_array, cb); + } + else + { + decreaseOpenItemCount(); + } + } } @@ -379,51 +379,51 @@ void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) static LLDefaultChildRegistry::Register r("inventory_link_replace_drop_target"); BOOL LLInventoryLinkReplaceDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - LLInventoryItem* item = (LLInventoryItem*)cargo_data; - - if (cargo_type >= DAD_TEXTURE && cargo_type <= DAD_LINK && - item && item->getActualType() != LLAssetType::AT_LINK_FOLDER && item->getType() != LLAssetType::AT_CATEGORY && - ( - LLAssetType::lookupCanLink(item->getType()) || - (item->getType() == LLAssetType::AT_LINK && !gInventory.getObject(item->getLinkedUUID())) // Broken Link! - )) - { - if (drop) - { - setItem(item); - if (!mDADSignal.empty()) - { - mDADSignal(mItemID); - } - } - else - { - *accept = ACCEPT_YES_SINGLE; - } - } - else - { - *accept = ACCEPT_NO; - } - - return TRUE; + LLInventoryItem* item = (LLInventoryItem*)cargo_data; + + if (cargo_type >= DAD_TEXTURE && cargo_type <= DAD_LINK && + item && item->getActualType() != LLAssetType::AT_LINK_FOLDER && item->getType() != LLAssetType::AT_CATEGORY && + ( + LLAssetType::lookupCanLink(item->getType()) || + (item->getType() == LLAssetType::AT_LINK && !gInventory.getObject(item->getLinkedUUID())) // Broken Link! + )) + { + if (drop) + { + setItem(item); + if (!mDADSignal.empty()) + { + mDADSignal(mItemID); + } + } + else + { + *accept = ACCEPT_YES_SINGLE; + } + } + else + { + *accept = ACCEPT_NO; + } + + return TRUE; } void LLInventoryLinkReplaceDropTarget::setItem(LLInventoryItem* item) { - if (item) - { - mItemID = item->getLinkedUUID(); - setText(item->getName()); - } - else - { - mItemID.setNull(); - setText(LLStringExplicit("")); - } + if (item) + { + mItemID = item->getLinkedUUID(); + setText(item->getName()); + } + else + { + mItemID.setNull(); + setText(LLStringExplicit("")); + } } diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index a11e025a71..e2fff20735 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2017&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2017, 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$ */ @@ -40,84 +40,84 @@ class LLTextBox; class LLInventoryLinkReplaceDropTarget : public LLLineEditor { public: - struct Params : public LLInitParam::Block - { - Params() - {} - }; - - LLInventoryLinkReplaceDropTarget(const Params& p) - : LLLineEditor(p) {} - ~LLInventoryLinkReplaceDropTarget() {} - - typedef boost::signals2::signal item_dad_callback_t; - boost::signals2::connection setDADCallback(const item_dad_callback_t::slot_type& cb) - { - return mDADSignal.connect(cb); - } - - virtual BOOL postBuild() - { - setEnabled(FALSE); - return LLLineEditor::postBuild(); - } - - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - LLUUID getItemID() const { return mItemID; } - void setItem(LLInventoryItem* item); + struct Params : public LLInitParam::Block + { + Params() + {} + }; + + LLInventoryLinkReplaceDropTarget(const Params& p) + : LLLineEditor(p) {} + ~LLInventoryLinkReplaceDropTarget() {} + + typedef boost::signals2::signal item_dad_callback_t; + boost::signals2::connection setDADCallback(const item_dad_callback_t::slot_type& cb) + { + return mDADSignal.connect(cb); + } + + virtual BOOL postBuild() + { + setEnabled(FALSE); + return LLLineEditor::postBuild(); + } + + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + LLUUID getItemID() const { return mItemID; } + void setItem(LLInventoryItem* item); private: - LLUUID mItemID; + LLUUID mItemID; - item_dad_callback_t mDADSignal; + item_dad_callback_t mDADSignal; }; class LLFloaterLinkReplace : public LLFloater, LLEventTimer { - LOG_CLASS(LLFloaterLinkReplace); + LOG_CLASS(LLFloaterLinkReplace); public: - LLFloaterLinkReplace(const LLSD& key); - virtual ~LLFloaterLinkReplace(); + LLFloaterLinkReplace(const LLSD& key); + virtual ~LLFloaterLinkReplace(); - BOOL postBuild() override; - void onOpen(const LLSD& key) override; + BOOL postBuild() override; + void onOpen(const LLSD& key) override; - bool tick() override; + bool tick() override; private: - void checkEnableStart(); - void onStartClicked(); - void onStartClickedResponse(const LLSD& notification, const LLSD& response); - void decreaseOpenItemCount(); - void updateFoundLinks(); - void processBatch(LLInventoryModel::item_array_t items); - - static void linkCreatedCallback(LLHandle floater_handle, const LLUUID& old_item_id, const LLUUID& target_item_id, - bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id); - static void itemRemovedCallback(LLHandle floater_handle, const LLUUID& outfit_folder_id); - - void onSourceItemDrop(const LLUUID& source_item_id); - void onTargetItemDrop(const LLUUID& target_item_id); - - LLInventoryLinkReplaceDropTarget* mSourceEditor; - LLInventoryLinkReplaceDropTarget* mTargetEditor; - LLButton* mStartBtn; - LLButton* mRefreshBtn; - LLTextBox* mStatusText; - - LLUUID mSourceUUID; - LLUUID mTargetUUID; - U32 mRemainingItems; - U32 mBatchSize; - - LLInventoryModel::item_array_t mRemainingInventoryItems; + void checkEnableStart(); + void onStartClicked(); + void onStartClickedResponse(const LLSD& notification, const LLSD& response); + void decreaseOpenItemCount(); + void updateFoundLinks(); + void processBatch(LLInventoryModel::item_array_t items); + + static void linkCreatedCallback(LLHandle floater_handle, const LLUUID& old_item_id, const LLUUID& target_item_id, + bool needs_wearable_ordering_update, bool needs_description_update, const LLUUID& outfit_folder_id); + static void itemRemovedCallback(LLHandle floater_handle, const LLUUID& outfit_folder_id); + + void onSourceItemDrop(const LLUUID& source_item_id); + void onTargetItemDrop(const LLUUID& target_item_id); + + LLInventoryLinkReplaceDropTarget* mSourceEditor; + LLInventoryLinkReplaceDropTarget* mTargetEditor; + LLButton* mStartBtn; + LLButton* mRefreshBtn; + LLTextBox* mStatusText; + + LLUUID mSourceUUID; + LLUUID mTargetUUID; + U32 mRemainingItems; + U32 mBatchSize; + + LLInventoryModel::item_array_t mRemainingInventoryItems; }; #endif // LL_FLOATERLINKREPLACE_H diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index 6fd11dd1c7..60571d6247 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llfloaterluadebug.cpp * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2023, 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$ */ @@ -72,7 +72,7 @@ BOOL LLFloaterLUADebug::postBuild() return TRUE; } -LLFloaterLUADebug::~LLFloaterLUADebug() +LLFloaterLUADebug::~LLFloaterLUADebug() {} void LLFloaterLUADebug::onExecuteClicked() @@ -80,7 +80,7 @@ void LLFloaterLUADebug::onExecuteClicked() mResultOutput->setValue(""); std::string cmd = mLineInput->getText(); - cleanLuaState(); + cleanLuaState(); LLLUAmanager::runScriptLine(mState, cmd, [this](int count, const LLSD& result) { completion(count, result); @@ -94,17 +94,17 @@ void LLFloaterLUADebug::onBtnBrowse() void LLFloaterLUADebug::onBtnRun() { - std::vector filenames; - std::string filepath = mScriptPath->getText(); - if (!filepath.empty()) - { - filenames.push_back(filepath); - runSelectedScript(filenames); - } + std::vector filenames; + std::string filepath = mScriptPath->getText(); + if (!filepath.empty()) + { + filenames.push_back(filepath); + runSelectedScript(filenames); + } } void LLFloaterLUADebug::runSelectedScript(const std::vector &filenames) -{ +{ mResultOutput->setValue(""); std::string filepath = filenames[0]; @@ -145,9 +145,9 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) } } -void LLFloaterLUADebug::cleanLuaState() -{ - if(getChild("clean_lua_state")->get()) +void LLFloaterLUADebug::cleanLuaState() +{ + if(getChild("clean_lua_state")->get()) { //Reinit to clean lua_State mState.initLuaState(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index d9f7f0a171..7e3f35e0fc 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterpreference.cpp * @brief Global preferences with and without persistence. * * $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$ */ @@ -159,14 +159,14 @@ struct LabelTable : public LLInitParam::Block }; -// global functions +// global functions // helper functions for getting/freeing the web browser media // if creating/destroying these is too slow, we'll need to create // a static member and update all our static callbacks -void handleNameTagOptionChanged(const LLSD& newvalue); -void handleDisplayNamesOptionChanged(const LLSD& newvalue); +void handleNameTagOptionChanged(const LLSD& newvalue); +void handleDisplayNamesOptionChanged(const LLSD& newvalue); bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response); bool callback_clear_cache(const LLSD& notification, const LLSD& response); @@ -177,79 +177,79 @@ void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); bool callback_clear_cache(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - // flag client texture cache for clearing next time the client runs - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); - LLNotificationsUtil::add("CacheWillClear"); - } + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + // flag client texture cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotificationsUtil::add("CacheWillClear"); + } - return false; + return false; } bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - // clean web - LLViewerMedia::getInstance()->clearAllCaches(); - LLViewerMedia::getInstance()->clearAllCookies(); - - // clean nav bar history - LLNavigationBar::getInstance()->clearHistoryCache(); - - // flag client texture cache for clearing next time the client runs - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); - LLNotificationsUtil::add("CacheWillClear"); - - LLSearchHistory::getInstance()->clearHistory(); - LLSearchHistory::getInstance()->save(); - LLSearchComboBox* search_ctrl = LLNavigationBar::getInstance()->getChild("search_combo_box"); - search_ctrl->clearHistory(); - - LLTeleportHistoryStorage::getInstance()->purgeItems(); - LLTeleportHistoryStorage::getInstance()->save(); - } - - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + // clean web + LLViewerMedia::getInstance()->clearAllCaches(); + LLViewerMedia::getInstance()->clearAllCookies(); + + // clean nav bar history + LLNavigationBar::getInstance()->clearHistoryCache(); + + // flag client texture cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotificationsUtil::add("CacheWillClear"); + + LLSearchHistory::getInstance()->clearHistory(); + LLSearchHistory::getInstance()->save(); + LLSearchComboBox* search_ctrl = LLNavigationBar::getInstance()->getChild("search_combo_box"); + search_ctrl->clearHistory(); + + LLTeleportHistoryStorage::getInstance()->purgeItems(); + LLTeleportHistoryStorage::getInstance()->save(); + } + + return false; } void handleNameTagOptionChanged(const LLSD& newvalue) { - LLAvatarNameCache::getInstance()->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); - LLVOAvatar::invalidateNameTags(); + LLAvatarNameCache::getInstance()->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + LLVOAvatar::invalidateNameTags(); } void handleDisplayNamesOptionChanged(const LLSD& newvalue) { - LLAvatarNameCache::getInstance()->setUseDisplayNames(newvalue.asBoolean()); - LLVOAvatar::invalidateNameTags(); + LLAvatarNameCache::getInstance()->setUseDisplayNames(newvalue.asBoolean()); + LLVOAvatar::invalidateNameTags(); } void handleAppearanceCameraMovementChanged(const LLSD& newvalue) { - if(!newvalue.asBoolean() && gAgentCamera.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR) - { - gAgentCamera.changeCameraToDefault(); - gAgentCamera.resetView(); - } + if(!newvalue.asBoolean() && gAgentCamera.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR) + { + gAgentCamera.changeCameraToDefault(); + gAgentCamera.resetView(); + } } void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { - numerator = 0; - denominator = 0; - for (F32 test_denominator = 1.f; test_denominator < 30.f; test_denominator += 1.f) - { - if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f) - { - numerator = ll_round(decimal_val * test_denominator); - denominator = ll_round(test_denominator); - break; - } - } + numerator = 0; + denominator = 0; + for (F32 test_denominator = 1.f; test_denominator < 30.f; test_denominator += 1.f) + { + if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f) + { + numerator = ll_round(decimal_val * test_denominator); + denominator = ll_round(test_denominator); + break; + } + } } // handle secondlife:///app/worldmap/{NAME}/{COORDS} URLs @@ -295,89 +295,89 @@ LLKeybindingHandler gKeybindHandler; std::string LLFloaterPreference::sSkin = ""; LLFloaterPreference::LLFloaterPreference(const LLSD& key) - : LLFloater(key), - mGotPersonalInfo(false), - mLanguageChanged(false), - mAvatarDataInitialized(false), - mSearchDataDirty(true) -{ - LLConversationLog::instance().addObserver(this); - - //Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - static bool registered_dialog = false; - if (!registered_dialog) - { - LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - registered_dialog = true; - } - - mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this, _2)); - mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this, _2)); - - mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); - mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); - mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); - mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); - mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); - mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); - mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); - mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); - mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); - mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); - mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); - mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); - mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); - mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); + : LLFloater(key), + mGotPersonalInfo(false), + mLanguageChanged(false), + mAvatarDataInitialized(false), + mSearchDataDirty(true) +{ + LLConversationLog::instance().addObserver(this); + + //Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + static bool registered_dialog = false; + if (!registered_dialog) + { + LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + registered_dialog = true; + } + + mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this, _2)); + mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this, _2)); + + mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); + mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); + mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); + mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); + mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); + mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); + mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); + mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); + mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); + mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); + mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); + mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); + mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); + mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreference::onRenderOptionEnable, this)); - mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); - mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this)); - mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); - mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); - mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); - mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); - mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); - mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); - mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); - mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); - mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); - mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); - mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); - - sSkin = gSavedSettings.getString("SkinCurrent"); - - mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); - - gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); - gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); - gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); - - gSavedSettings.getControl("AppearanceCameraMovement")->getCommitSignal()->connect(boost::bind(&handleAppearanceCameraMovementChanged, _2)); + mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); + mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this)); + mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); + mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2)); + mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2)); + mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this)); + mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); + mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); + mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); + mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); + mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); + mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); + mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); + + sSkin = gSavedSettings.getString("SkinCurrent"); + + mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); + + gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); + gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); + gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); + + gSavedSettings.getControl("AppearanceCameraMovement")->getCommitSignal()->connect(boost::bind(&handleAppearanceCameraMovementChanged, _2)); gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::onAtmosShaderChange, this)); - LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); + LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); - mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); - mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); - mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // Hook up for filtering + mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); + mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); + mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // Hook up for filtering } void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type ) { - if ( APT_PROPERTIES == type ) - { - const LLAvatarData* pAvatarData = static_cast( pData ); - if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) - { + if ( APT_PROPERTIES == type ) + { + const LLAvatarData* pAvatarData = static_cast( pData ); + if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) + { mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH); mAvatarDataInitialized = true; getChild("online_searchresults")->setValue(mAllowPublish); - } - } + } + } } void LLFloaterPreference::saveAvatarProperties( void ) @@ -430,247 +430,247 @@ void LLFloaterPreference::saveAvatarPropertiesCoro(const std::string cap_url, bo BOOL LLFloaterPreference::postBuild() { - gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); + gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); - gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged)); + gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged)); - gSavedSettings.getControl("ChatBubbleOpacity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onNameTagOpacityChange, this, _2)); + gSavedSettings.getControl("ChatBubbleOpacity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onNameTagOpacityChange, this, _2)); - gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeMaturity, this)); + gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeMaturity, this)); - gSavedPerAccountSettings.getControl("ModelUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeModelFolder, this)); + gSavedPerAccountSettings.getControl("ModelUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeModelFolder, this)); gSavedPerAccountSettings.getControl("PBRUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangePBRFolder, this)); - gSavedPerAccountSettings.getControl("TextureUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeTextureFolder, this)); - gSavedPerAccountSettings.getControl("SoundUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeSoundFolder, this)); - gSavedPerAccountSettings.getControl("AnimationUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeAnimationFolder, this)); - - LLTabContainer* tabcontainer = getChild("pref core"); - if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) - tabcontainer->selectFirstTab(); - - getChild("cache_location")->setEnabled(FALSE); // make it read-only but selectable (STORM-227) - std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); - setCacheLocation(cache_location); - - getChild("log_path_string")->setEnabled(FALSE); // make it read-only but selectable - - getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); - - getChild("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); - getChild("NonFriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NonFriendIMOptions")); - getChild("ConferenceIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ConferenceIMOptions")); - getChild("GroupChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"GroupChatOptions")); - getChild("NearbyChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NearbyChatOptions")); - getChild("ObjectIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ObjectIMOptions")); - - // if floater is opened before login set default localized do not disturb message - if (LLStartUp::getStartupState() < STATE_STARTED) - { - gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); - } - - // set 'enable' property for 'Clear log...' button - changed(); - - LLLogChat::getInstance()->setSaveHistorySignal(boost::bind(&LLFloaterPreference::onLogChatHistorySaved, this)); - - LLSliderCtrl* fov_slider = getChild("camera_fov"); - fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); - fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); - - // Hook up and init for filtering - mFilterEdit = getChild("search_prefs_edit"); - mFilterEdit->setKeystrokeCallback(boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); - - // Load and assign label for 'default language' - std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "default_languages.xml"); - std::map labels; - if (loadFromFilename(user_filename, labels)) - { - std::string system_lang = gSavedSettings.getString("SystemLanguage"); - std::map::iterator iter = labels.find(system_lang); - if (iter != labels.end()) - { - getChild("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true); - } - else - { - LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL; - getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); - } - } - else - { - LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL; - getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); - } - - return TRUE; + gSavedPerAccountSettings.getControl("TextureUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeTextureFolder, this)); + gSavedPerAccountSettings.getControl("SoundUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeSoundFolder, this)); + gSavedPerAccountSettings.getControl("AnimationUploadFolder")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeAnimationFolder, this)); + + LLTabContainer* tabcontainer = getChild("pref core"); + if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) + tabcontainer->selectFirstTab(); + + getChild("cache_location")->setEnabled(FALSE); // make it read-only but selectable (STORM-227) + std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); + setCacheLocation(cache_location); + + getChild("log_path_string")->setEnabled(FALSE); // make it read-only but selectable + + getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); + + getChild("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); + getChild("NonFriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NonFriendIMOptions")); + getChild("ConferenceIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ConferenceIMOptions")); + getChild("GroupChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"GroupChatOptions")); + getChild("NearbyChatOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NearbyChatOptions")); + getChild("ObjectIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"ObjectIMOptions")); + + // if floater is opened before login set default localized do not disturb message + if (LLStartUp::getStartupState() < STATE_STARTED) + { + gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); + } + + // set 'enable' property for 'Clear log...' button + changed(); + + LLLogChat::getInstance()->setSaveHistorySignal(boost::bind(&LLFloaterPreference::onLogChatHistorySaved, this)); + + LLSliderCtrl* fov_slider = getChild("camera_fov"); + fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); + fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); + + // Hook up and init for filtering + mFilterEdit = getChild("search_prefs_edit"); + mFilterEdit->setKeystrokeCallback(boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); + + // Load and assign label for 'default language' + std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "default_languages.xml"); + std::map labels; + if (loadFromFilename(user_filename, labels)) + { + std::string system_lang = gSavedSettings.getString("SystemLanguage"); + std::map::iterator iter = labels.find(system_lang); + if (iter != labels.end()) + { + getChild("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true); + } + else + { + LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL; + getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + } + } + else + { + LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL; + getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + } + + return TRUE; } void LLFloaterPreference::updateDeleteTranscriptsButton() { - std::vector list_of_transcriptions_file_names; - LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names); - getChild("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0); + std::vector list_of_transcriptions_file_names; + LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names); + getChild("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0); } void LLFloaterPreference::onDoNotDisturbResponseChanged() { - // set "DoNotDisturbResponseChanged" TRUE if user edited message differs from default, FALSE otherwise - bool response_changed_flag = - LLTrans::getString("DoNotDisturbModeResponseDefault") - != getChild("do_not_disturb_response")->getValue().asString(); + // set "DoNotDisturbResponseChanged" TRUE if user edited message differs from default, FALSE otherwise + bool response_changed_flag = + LLTrans::getString("DoNotDisturbModeResponseDefault") + != getChild("do_not_disturb_response")->getValue().asString(); - gSavedPerAccountSettings.setBOOL("DoNotDisturbResponseChanged", response_changed_flag ); + gSavedPerAccountSettings.setBOOL("DoNotDisturbResponseChanged", response_changed_flag ); } LLFloaterPreference::~LLFloaterPreference() { - LLConversationLog::instance().removeObserver(this); + LLConversationLog::instance().removeObserver(this); mComplexityChangedSignal.disconnect(); } void LLFloaterPreference::draw() { - BOOL has_first_selected = (getChildRef("disabled_popups").getFirstSelected()!=NULL); - gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected); - - has_first_selected = (getChildRef("enabled_popups").getFirstSelected()!=NULL); - gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected); - - LLFloater::draw(); + BOOL has_first_selected = (getChildRef("disabled_popups").getFirstSelected()!=NULL); + gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected); + + has_first_selected = (getChildRef("enabled_popups").getFirstSelected()!=NULL); + gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected); + + LLFloater::draw(); } void LLFloaterPreference::saveSettings() { - LLTabContainer* tabcontainer = getChild("pref core"); - child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - child_list_t::const_iterator end = tabcontainer->getChildList()->end(); - for ( ; iter != end; ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast(view); - if (panel) - panel->saveSettings(); - } + LLTabContainer* tabcontainer = getChild("pref core"); + child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + child_list_t::const_iterator end = tabcontainer->getChildList()->end(); + for ( ; iter != end; ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast(view); + if (panel) + panel->saveSettings(); + } saveIgnoredNotifications(); -} +} void LLFloaterPreference::apply() { - LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); - - LLTabContainer* tabcontainer = getChild("pref core"); - if (sSkin != gSavedSettings.getString("SkinCurrent")) - { - LLNotificationsUtil::add("ChangeSkin"); - refreshSkin(this); - } - // Call apply() on all panels that derive from LLPanelPreference - for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - iter != tabcontainer->getChildList()->end(); ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast(view); - if (panel) - panel->apply(); - } - - gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor - - LLSliderCtrl* fov_slider = getChild("camera_fov"); - fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); - fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); - - std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); - setCacheLocation(cache_location); - - LLViewerMedia::getInstance()->setCookiesEnabled(getChild("cookies_enabled")->getValue()); - - if (hasChild("web_proxy_enabled", TRUE) &&hasChild("web_proxy_editor", TRUE) && hasChild("web_proxy_port", TRUE)) - { - bool proxy_enable = getChild("web_proxy_enabled")->getValue(); - std::string proxy_address = getChild("web_proxy_editor")->getValue(); - int proxy_port = getChild("web_proxy_port")->getValue(); - LLViewerMedia::getInstance()->setProxyConfig(proxy_enable, proxy_address, proxy_port); - } - - if (mGotPersonalInfo) - { - bool new_hide_online = getChild("online_visibility")->getValue().asBoolean(); - - if (new_hide_online != mOriginalHideOnlineStatus) - { - // This hack is because we are representing several different - // possible strings with a single checkbox. Since most users - // can only select between 2 values, we represent it as a - // checkbox. This breaks down a little bit for liaisons, but - // works out in the end. - if (new_hide_online != mOriginalHideOnlineStatus) - { - if (new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN; - else mDirectoryVisibility = VISIBILITY_DEFAULT; - //Update showonline value, otherwise multiple applys won't work - mOriginalHideOnlineStatus = new_hide_online; - } - gAgent.sendAgentUpdateUserInfo(mDirectoryVisibility); - } - } - - saveAvatarProperties(); + LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); + + LLTabContainer* tabcontainer = getChild("pref core"); + if (sSkin != gSavedSettings.getString("SkinCurrent")) + { + LLNotificationsUtil::add("ChangeSkin"); + refreshSkin(this); + } + // Call apply() on all panels that derive from LLPanelPreference + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast(view); + if (panel) + panel->apply(); + } + + gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor + + LLSliderCtrl* fov_slider = getChild("camera_fov"); + fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); + fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); + + std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); + setCacheLocation(cache_location); + + LLViewerMedia::getInstance()->setCookiesEnabled(getChild("cookies_enabled")->getValue()); + + if (hasChild("web_proxy_enabled", TRUE) &&hasChild("web_proxy_editor", TRUE) && hasChild("web_proxy_port", TRUE)) + { + bool proxy_enable = getChild("web_proxy_enabled")->getValue(); + std::string proxy_address = getChild("web_proxy_editor")->getValue(); + int proxy_port = getChild("web_proxy_port")->getValue(); + LLViewerMedia::getInstance()->setProxyConfig(proxy_enable, proxy_address, proxy_port); + } + + if (mGotPersonalInfo) + { + bool new_hide_online = getChild("online_visibility")->getValue().asBoolean(); + + if (new_hide_online != mOriginalHideOnlineStatus) + { + // This hack is because we are representing several different + // possible strings with a single checkbox. Since most users + // can only select between 2 values, we represent it as a + // checkbox. This breaks down a little bit for liaisons, but + // works out in the end. + if (new_hide_online != mOriginalHideOnlineStatus) + { + if (new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN; + else mDirectoryVisibility = VISIBILITY_DEFAULT; + //Update showonline value, otherwise multiple applys won't work + mOriginalHideOnlineStatus = new_hide_online; + } + gAgent.sendAgentUpdateUserInfo(mDirectoryVisibility); + } + } + + saveAvatarProperties(); } void LLFloaterPreference::cancel() { - LLTabContainer* tabcontainer = getChild("pref core"); - // Call cancel() on all panels that derive from LLPanelPreference - for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - iter != tabcontainer->getChildList()->end(); ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast(view); - if (panel) - panel->cancel(); - } - // hide joystick pref floater - LLFloaterReg::hideInstance("pref_joystick"); - - // hide translation settings floater - LLFloaterReg::hideInstance("prefs_translation"); - - // hide autoreplace settings floater - LLFloaterReg::hideInstance("prefs_autoreplace"); - - // hide spellchecker settings folder - LLFloaterReg::hideInstance("prefs_spellchecker"); - - // hide advanced graphics floater - LLFloaterReg::hideInstance("prefs_graphics_advanced"); - - // reverts any changes to current skin - gSavedSettings.setString("SkinCurrent", sSkin); - - updateClickActionViews(); - - LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance("prefs_proxy"); - if (advanced_proxy_settings) - { - advanced_proxy_settings->cancel(); - } - //Need to reload the navmesh if the pathing console is up - LLHandle pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); - if ( !pathfindingConsoleHandle.isDead() ) - { - LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); - pPathfindingConsole->onRegionBoundaryCross(); - } - - if (!mSavedGraphicsPreset.empty()) - { - gSavedSettings.setString("PresetGraphicActive", mSavedGraphicsPreset); - LLPresetsManager::getInstance()->triggerChangeSignal(); - } + LLTabContainer* tabcontainer = getChild("pref core"); + // Call cancel() on all panels that derive from LLPanelPreference + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast(view); + if (panel) + panel->cancel(); + } + // hide joystick pref floater + LLFloaterReg::hideInstance("pref_joystick"); + + // hide translation settings floater + LLFloaterReg::hideInstance("prefs_translation"); + + // hide autoreplace settings floater + LLFloaterReg::hideInstance("prefs_autoreplace"); + + // hide spellchecker settings folder + LLFloaterReg::hideInstance("prefs_spellchecker"); + + // hide advanced graphics floater + LLFloaterReg::hideInstance("prefs_graphics_advanced"); + + // reverts any changes to current skin + gSavedSettings.setString("SkinCurrent", sSkin); + + updateClickActionViews(); + + LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance("prefs_proxy"); + if (advanced_proxy_settings) + { + advanced_proxy_settings->cancel(); + } + //Need to reload the navmesh if the pathing console is up + LLHandle pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if ( !pathfindingConsoleHandle.isDead() ) + { + LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); + pPathfindingConsole->onRegionBoundaryCross(); + } + + if (!mSavedGraphicsPreset.empty()) + { + gSavedSettings.setString("PresetGraphicActive", mSavedGraphicsPreset); + LLPresetsManager::getInstance()->triggerChangeSignal(); + } restoreIgnoredNotifications(); } @@ -678,157 +678,157 @@ void LLFloaterPreference::cancel() void LLFloaterPreference::onOpen(const LLSD& key) { - // this variable and if that follows it are used to properly handle do not disturb mode response message - static bool initialized = FALSE; - // if user is logged in and we haven't initialized do not disturb mode response yet, do it - if (!initialized && LLStartUp::getStartupState() == STATE_STARTED) - { - // Special approach is used for do not disturb response localization, because "DoNotDisturbModeResponse" is - // in non-localizable xml, and also because it may be changed by user and in this case it shouldn't be localized. - // To keep track of whether do not disturb response is default or changed by user additional setting DoNotDisturbResponseChanged - // was added into per account settings. - - // initialization should happen once,so setting variable to TRUE - initialized = TRUE; - // this connection is needed to properly set "DoNotDisturbResponseChanged" setting when user makes changes in - // do not disturb response message. - gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->getSignal()->connect(boost::bind(&LLFloaterPreference::onDoNotDisturbResponseChanged, this)); - } - gAgent.sendAgentUserInfoRequest(); - - /////////////////////////// From LLPanelGeneral ////////////////////////// - // if we have no agent, we can't let them choose anything - // if we have an agent, then we only let them choose if they have a choice - bool can_choose_maturity = - gAgent.getID().notNull() && - (gAgent.isMature() || gAgent.isGodlike()); - - LLComboBox* maturity_combo = getChild("maturity_desired_combobox"); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() ); - if (can_choose_maturity) - { - // if they're not adult or a god, they shouldn't see the adult selection, so delete it - if (!gAgent.isAdult() && !gAgent.isGodlikeWithoutAdminMenuFakery()) - { - // we're going to remove the adult entry from the combo - LLScrollListCtrl* maturity_list = maturity_combo->findChild("ComboBox"); - if (maturity_list) - { - maturity_list->deleteItems(LLSD(SIM_ACCESS_ADULT)); - } - } - getChildView("maturity_desired_combobox")->setEnabled( true); - getChildView("maturity_desired_textbox")->setVisible( false); - } - else - { - getChild("maturity_desired_textbox")->setValue(maturity_combo->getSelectedItemLabel()); - getChildView("maturity_desired_combobox")->setEnabled( false); - } - - // Forget previous language changes. - mLanguageChanged = false; - - // Display selected maturity icons. - onChangeMaturity(); - - onChangeModelFolder(); + // this variable and if that follows it are used to properly handle do not disturb mode response message + static bool initialized = FALSE; + // if user is logged in and we haven't initialized do not disturb mode response yet, do it + if (!initialized && LLStartUp::getStartupState() == STATE_STARTED) + { + // Special approach is used for do not disturb response localization, because "DoNotDisturbModeResponse" is + // in non-localizable xml, and also because it may be changed by user and in this case it shouldn't be localized. + // To keep track of whether do not disturb response is default or changed by user additional setting DoNotDisturbResponseChanged + // was added into per account settings. + + // initialization should happen once,so setting variable to TRUE + initialized = TRUE; + // this connection is needed to properly set "DoNotDisturbResponseChanged" setting when user makes changes in + // do not disturb response message. + gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->getSignal()->connect(boost::bind(&LLFloaterPreference::onDoNotDisturbResponseChanged, this)); + } + gAgent.sendAgentUserInfoRequest(); + + /////////////////////////// From LLPanelGeneral ////////////////////////// + // if we have no agent, we can't let them choose anything + // if we have an agent, then we only let them choose if they have a choice + bool can_choose_maturity = + gAgent.getID().notNull() && + (gAgent.isMature() || gAgent.isGodlike()); + + LLComboBox* maturity_combo = getChild("maturity_desired_combobox"); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() ); + if (can_choose_maturity) + { + // if they're not adult or a god, they shouldn't see the adult selection, so delete it + if (!gAgent.isAdult() && !gAgent.isGodlikeWithoutAdminMenuFakery()) + { + // we're going to remove the adult entry from the combo + LLScrollListCtrl* maturity_list = maturity_combo->findChild("ComboBox"); + if (maturity_list) + { + maturity_list->deleteItems(LLSD(SIM_ACCESS_ADULT)); + } + } + getChildView("maturity_desired_combobox")->setEnabled( true); + getChildView("maturity_desired_textbox")->setVisible( false); + } + else + { + getChild("maturity_desired_textbox")->setValue(maturity_combo->getSelectedItemLabel()); + getChildView("maturity_desired_combobox")->setEnabled( false); + } + + // Forget previous language changes. + mLanguageChanged = false; + + // Display selected maturity icons. + onChangeMaturity(); + + onChangeModelFolder(); onChangePBRFolder(); - onChangeTextureFolder(); - onChangeSoundFolder(); - onChangeAnimationFolder(); - - // Load (double-)click to walk/teleport settings. - updateClickActionViews(); - - // Enabled/disabled popups, might have been changed by user actions - // while preferences floater was closed. - buildPopupLists(); - - - //get the options that were checked - onNotificationsChange("FriendIMOptions"); - onNotificationsChange("NonFriendIMOptions"); - onNotificationsChange("ConferenceIMOptions"); - onNotificationsChange("GroupChatOptions"); - onNotificationsChange("NearbyChatOptions"); - onNotificationsChange("ObjectIMOptions"); - - LLPanelLogin::setAlwaysRefresh(true); - refresh(); - - // Make sure the current state of prefs are saved away when - // when the floater is opened. That will make cancel do its - // job - saveSettings(); - - // Make sure there is a default preference file - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_GRAPHIC); - - bool started = (LLStartUp::getStartupState() == STATE_STARTED); - - LLButton* load_btn = findChild("PrefLoadButton"); - LLButton* save_btn = findChild("PrefSaveButton"); - LLButton* delete_btn = findChild("PrefDeleteButton"); - LLButton* exceptions_btn = findChild("RenderExceptionsButton"); + onChangeTextureFolder(); + onChangeSoundFolder(); + onChangeAnimationFolder(); + + // Load (double-)click to walk/teleport settings. + updateClickActionViews(); + + // Enabled/disabled popups, might have been changed by user actions + // while preferences floater was closed. + buildPopupLists(); + + + //get the options that were checked + onNotificationsChange("FriendIMOptions"); + onNotificationsChange("NonFriendIMOptions"); + onNotificationsChange("ConferenceIMOptions"); + onNotificationsChange("GroupChatOptions"); + onNotificationsChange("NearbyChatOptions"); + onNotificationsChange("ObjectIMOptions"); + + LLPanelLogin::setAlwaysRefresh(true); + refresh(); + + // Make sure the current state of prefs are saved away when + // when the floater is opened. That will make cancel do its + // job + saveSettings(); + + // Make sure there is a default preference file + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_GRAPHIC); + + bool started = (LLStartUp::getStartupState() == STATE_STARTED); + + LLButton* load_btn = findChild("PrefLoadButton"); + LLButton* save_btn = findChild("PrefSaveButton"); + LLButton* delete_btn = findChild("PrefDeleteButton"); + LLButton* exceptions_btn = findChild("RenderExceptionsButton"); LLButton* auto_adjustments_btn = findChild("AutoAdjustmentsButton"); - if (load_btn && save_btn && delete_btn && exceptions_btn && auto_adjustments_btn) - { - load_btn->setEnabled(started); - save_btn->setEnabled(started); - delete_btn->setEnabled(started); - exceptions_btn->setEnabled(started); + if (load_btn && save_btn && delete_btn && exceptions_btn && auto_adjustments_btn) + { + load_btn->setEnabled(started); + save_btn->setEnabled(started); + delete_btn->setEnabled(started); + exceptions_btn->setEnabled(started); auto_adjustments_btn->setEnabled(started); - } + } collectSearchableItems(); - if (!mFilterEdit->getText().empty()) - { - mFilterEdit->setText(LLStringExplicit("")); - onUpdateFilterTerm(true); - } + if (!mFilterEdit->getText().empty()) + { + mFilterEdit->setText(LLStringExplicit("")); + onUpdateFilterTerm(true); + } } void LLFloaterPreference::onRenderOptionEnable() { - refreshEnabledGraphics(); + refreshEnabledGraphics(); } void LLFloaterPreference::onAvatarImpostorsEnable() { - refreshEnabledGraphics(); + refreshEnabledGraphics(); } //static void LLFloaterPreference::initDoNotDisturbResponse() - { - if (!gSavedPerAccountSettings.getBOOL("DoNotDisturbResponseChanged")) - { - //LLTrans::getString("DoNotDisturbModeResponseDefault") is used here for localization (EXT-5885) - gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); - } - } - -//static + { + if (!gSavedPerAccountSettings.getBOOL("DoNotDisturbResponseChanged")) + { + //LLTrans::getString("DoNotDisturbModeResponseDefault") is used here for localization (EXT-5885) + gSavedPerAccountSettings.setString("DoNotDisturbModeResponse", LLTrans::getString("DoNotDisturbModeResponseDefault")); + } + } + +//static void LLFloaterPreference::updateShowFavoritesCheckbox(bool val) { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->getChild("favorites_on_login_check")->setValue(val); - } + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->getChild("favorites_on_login_check")->setValue(val); + } } void LLFloaterPreference::setHardwareDefaults() { - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - if (!preset_graphic_active.empty()) - { - saveGraphicsPreset(preset_graphic_active); - saveSettings(); // save here to be able to return to the previous preset by Cancel - } + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + if (!preset_graphic_active.empty()) + { + saveGraphicsPreset(preset_graphic_active); + saveSettings(); // save here to be able to return to the previous preset by Cancel + } setRecommendedSettings(); } @@ -837,27 +837,27 @@ void LLFloaterPreference::setRecommendedSettings() resetAutotuneSettings(); gSavedSettings.getControl("RenderVSyncEnable")->resetToDefault(true); - LLFeatureManager::getInstance()->applyRecommendedSettings(); + LLFeatureManager::getInstance()->applyRecommendedSettings(); - // reset indirects before refresh because we may have changed what they control - LLAvatarComplexityControls::setIndirectControls(); + // reset indirects before refresh because we may have changed what they control + LLAvatarComplexityControls::setIndirectControls(); - refreshEnabledGraphics(); - gSavedSettings.setString("PresetGraphicActive", ""); - LLPresetsManager::getInstance()->triggerChangeSignal(); + refreshEnabledGraphics(); + gSavedSettings.setString("PresetGraphicActive", ""); + LLPresetsManager::getInstance()->triggerChangeSignal(); - LLTabContainer* tabcontainer = getChild("pref core"); - child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - child_list_t::const_iterator end = tabcontainer->getChildList()->end(); - for ( ; iter != end; ++iter) - { - LLView* view = *iter; - LLPanelPreference* panel = dynamic_cast(view); - if (panel) - { - panel->setHardwareDefaults(); - } - } + LLTabContainer* tabcontainer = getChild("pref core"); + child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + child_list_t::const_iterator end = tabcontainer->getChildList()->end(); + for ( ; iter != end; ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast(view); + if (panel) + { + panel->setHardwareDefaults(); + } + } } void LLFloaterPreference::resetAutotuneSettings() @@ -884,452 +884,452 @@ void LLFloaterPreference::resetAutotuneSettings() void LLFloaterPreference::getControlNames(std::vector& names) { - LLView* view = findChild("display"); - LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - if (view && advanced) - { - std::list stack; - stack.push_back(view); - stack.push_back(advanced); - while(!stack.empty()) - { - // Process view on top of the stack - LLView* curview = stack.front(); - stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast(curview); - if (ctrl) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - std::string control_name = control->getName(); - if (std::find(names.begin(), names.end(), control_name) == names.end()) - { - names.push_back(control_name); - } - } - } - - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - stack.push_back(*iter); - } - } - } + LLView* view = findChild("display"); + LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); + if (view && advanced) + { + std::list stack; + stack.push_back(view); + stack.push_back(advanced); + while(!stack.empty()) + { + // Process view on top of the stack + LLView* curview = stack.front(); + stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + std::string control_name = control->getName(); + if (std::find(names.begin(), names.end(), control_name) == names.end()) + { + names.push_back(control_name); + } + } + } + + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + stack.push_back(*iter); + } + } + } } //virtual void LLFloaterPreference::onClose(bool app_quitting) { - gSavedSettings.setS32("LastPrefTab", getChild("pref core")->getCurrentPanelIndex()); - LLPanelLogin::setAlwaysRefresh(false); - if (!app_quitting) - { - cancel(); - } + gSavedSettings.setS32("LastPrefTab", getChild("pref core")->getCurrentPanelIndex()); + LLPanelLogin::setAlwaysRefresh(false); + if (!app_quitting) + { + cancel(); + } } -// static +// static void LLFloaterPreference::onBtnOK(const LLSD& userdata) { - // commit any outstanding text entry - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - } - - if (canClose()) - { - saveSettings(); - apply(); - - if (userdata.asString() == "closeadvanced") - { - LLFloaterReg::hideInstance("prefs_graphics_advanced"); - } - else - { - closeFloater(false); - } - - //Conversation transcript and log path changed so reload conversations based on new location - if(mPriorInstantMessageLogPath.length()) - { - if(moveTranscriptsAndLog()) - { - //When floaters are empty but have a chat history files, reload chat history into them - LLFloaterIMSessionTab::reloadEmptyFloaters(); - } - //Couldn't move files so restore the old path and show a notification - else - { - gSavedPerAccountSettings.setString("InstantMessageLogPath", mPriorInstantMessageLogPath); - LLNotificationsUtil::add("PreferenceChatPathChanged"); - } - mPriorInstantMessageLogPath.clear(); - } - - LLUIColorTable::instance().saveUserSettings(); - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - - //Only save once logged in and loaded per account settings - if(mGotPersonalInfo) - { - gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - } - } - else - { - // Show beep, pop up dialog, etc. - LL_INFOS("Preferences") << "Can't close preferences!" << LL_ENDL; - } - - LLPanelLogin::updateLocationSelectorsVisibility(); - //Need to reload the navmesh if the pathing console is up - LLHandle pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); - if ( !pathfindingConsoleHandle.isDead() ) - { - LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); - pPathfindingConsole->onRegionBoundaryCross(); - } -} - -// static + // commit any outstanding text entry + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + } + + if (canClose()) + { + saveSettings(); + apply(); + + if (userdata.asString() == "closeadvanced") + { + LLFloaterReg::hideInstance("prefs_graphics_advanced"); + } + else + { + closeFloater(false); + } + + //Conversation transcript and log path changed so reload conversations based on new location + if(mPriorInstantMessageLogPath.length()) + { + if(moveTranscriptsAndLog()) + { + //When floaters are empty but have a chat history files, reload chat history into them + LLFloaterIMSessionTab::reloadEmptyFloaters(); + } + //Couldn't move files so restore the old path and show a notification + else + { + gSavedPerAccountSettings.setString("InstantMessageLogPath", mPriorInstantMessageLogPath); + LLNotificationsUtil::add("PreferenceChatPathChanged"); + } + mPriorInstantMessageLogPath.clear(); + } + + LLUIColorTable::instance().saveUserSettings(); + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + + //Only save once logged in and loaded per account settings + if(mGotPersonalInfo) + { + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + } + } + else + { + // Show beep, pop up dialog, etc. + LL_INFOS("Preferences") << "Can't close preferences!" << LL_ENDL; + } + + LLPanelLogin::updateLocationSelectorsVisibility(); + //Need to reload the navmesh if the pathing console is up + LLHandle pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if ( !pathfindingConsoleHandle.isDead() ) + { + LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get(); + pPathfindingConsole->onRegionBoundaryCross(); + } +} + +// static void LLFloaterPreference::onBtnCancel(const LLSD& userdata) { - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - refresh(); - } - cancel(); - - if (userdata.asString() == "closeadvanced") - { - LLFloaterReg::hideInstance("prefs_graphics_advanced"); - } - else - { - closeFloater(); - } -} - -// static + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + refresh(); + } + cancel(); + + if (userdata.asString() == "closeadvanced") + { + LLFloaterReg::hideInstance("prefs_graphics_advanced"); + } + else + { + closeFloater(); + } +} + +// static void LLFloaterPreference::updateUserInfo(const std::string& visibility) { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { instance->setPersonalInfo(visibility); - } + } } void LLFloaterPreference::refreshEnabledGraphics() { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->refresh(); - } + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->refresh(); + } - LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - if (advanced) - { - advanced->refresh(); - } + LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); + if (advanced) + { + advanced->refresh(); + } } void LLFloaterPreference::onClickClearCache() { - LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache); + LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache); } void LLFloaterPreference::onClickBrowserClearCache() { - LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache); + LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache); } // Called when user changes language via the combobox. void LLFloaterPreference::onLanguageChange() { - // Let the user know that the change will only take effect after restart. - // Do it only once so that we're not too irritating. - if (!mLanguageChanged) - { - LLNotificationsUtil::add("ChangeLanguage"); - mLanguageChanged = true; - } + // Let the user know that the change will only take effect after restart. + // Do it only once so that we're not too irritating. + if (!mLanguageChanged) + { + LLNotificationsUtil::add("ChangeLanguage"); + mLanguageChanged = true; + } } void LLFloaterPreference::onNotificationsChange(const std::string& OptionName) { - mNotificationOptions[OptionName] = getChild(OptionName)->getSelectedItemLabel(); + mNotificationOptions[OptionName] = getChild(OptionName)->getSelectedItemLabel(); - bool show_notifications_alert = true; - for (notifications_map::iterator it_notification = mNotificationOptions.begin(); it_notification != mNotificationOptions.end(); it_notification++) - { - if(it_notification->second != "No action") - { - show_notifications_alert = false; - break; - } - } + bool show_notifications_alert = true; + for (notifications_map::iterator it_notification = mNotificationOptions.begin(); it_notification != mNotificationOptions.end(); it_notification++) + { + if(it_notification->second != "No action") + { + show_notifications_alert = false; + break; + } + } - getChild("notifications_alert")->setVisible(show_notifications_alert); + getChild("notifications_alert")->setVisible(show_notifications_alert); } void LLFloaterPreference::onNameTagOpacityChange(const LLSD& newvalue) { - LLColorSwatchCtrl* color_swatch = findChild("background"); - if (color_swatch) - { - LLColor4 new_color = color_swatch->get(); - color_swatch->set( new_color.setAlpha(newvalue.asReal()) ); - } + LLColorSwatchCtrl* color_swatch = findChild("background"); + if (color_swatch) + { + LLColor4 new_color = color_swatch->get(); + color_swatch->set( new_color.setAlpha(newvalue.asReal()) ); + } } void LLFloaterPreference::onClickSetCache() { - std::string cur_name(gSavedSettings.getString("CacheLocation")); -// std::string cur_top_folder(gDirUtilp->getBaseFileName(cur_name)); - - std::string proposed_name(cur_name); + std::string cur_name(gSavedSettings.getString("CacheLocation")); +// std::string cur_top_folder(gDirUtilp->getBaseFileName(cur_name)); + + std::string proposed_name(cur_name); - (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeCachePath, this, _1, _2), proposed_name))->getFile(); + (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeCachePath, this, _1, _2), proposed_name))->getFile(); } void LLFloaterPreference::changeCachePath(const std::vector& filenames, std::string proposed_name) { - std::string dir_name = filenames[0]; - if (!dir_name.empty() && dir_name != proposed_name) - { - std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name)); - LLNotificationsUtil::add("CacheWillBeMoved"); - gSavedSettings.setString("NewCacheLocation", dir_name); - gSavedSettings.setString("NewCacheLocationTopFolder", new_top_folder); - } - else - { - std::string cache_location = gDirUtilp->getCacheDir(); - gSavedSettings.setString("CacheLocation", cache_location); - std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); - gSavedSettings.setString("CacheLocationTopFolder", top_folder); - } + std::string dir_name = filenames[0]; + if (!dir_name.empty() && dir_name != proposed_name) + { + std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name)); + LLNotificationsUtil::add("CacheWillBeMoved"); + gSavedSettings.setString("NewCacheLocation", dir_name); + gSavedSettings.setString("NewCacheLocationTopFolder", new_top_folder); + } + else + { + std::string cache_location = gDirUtilp->getCacheDir(); + gSavedSettings.setString("CacheLocation", cache_location); + std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); + gSavedSettings.setString("CacheLocationTopFolder", top_folder); + } } void LLFloaterPreference::onClickResetCache() { - if (gDirUtilp->getCacheDir(false) == gDirUtilp->getCacheDir(true)) - { - // The cache location was already the default. - return; - } - gSavedSettings.setString("NewCacheLocation", ""); - gSavedSettings.setString("NewCacheLocationTopFolder", ""); - LLNotificationsUtil::add("CacheWillBeMoved"); - std::string cache_location = gDirUtilp->getCacheDir(false); - gSavedSettings.setString("CacheLocation", cache_location); - std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); - gSavedSettings.setString("CacheLocationTopFolder", top_folder); + if (gDirUtilp->getCacheDir(false) == gDirUtilp->getCacheDir(true)) + { + // The cache location was already the default. + return; + } + gSavedSettings.setString("NewCacheLocation", ""); + gSavedSettings.setString("NewCacheLocationTopFolder", ""); + LLNotificationsUtil::add("CacheWillBeMoved"); + std::string cache_location = gDirUtilp->getCacheDir(false); + gSavedSettings.setString("CacheLocation", cache_location); + std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); + gSavedSettings.setString("CacheLocationTopFolder", top_folder); } void LLFloaterPreference::onClickSkin(LLUICtrl* ctrl, const LLSD& userdata) { - gSavedSettings.setString("SkinCurrent", userdata.asString()); - ctrl->setValue(userdata.asString()); + gSavedSettings.setString("SkinCurrent", userdata.asString()); + ctrl->setValue(userdata.asString()); } void LLFloaterPreference::onSelectSkin() { - std::string skin_selection = getChild("skin_selection")->getValue().asString(); - gSavedSettings.setString("SkinCurrent", skin_selection); + std::string skin_selection = getChild("skin_selection")->getValue().asString(); + gSavedSettings.setString("SkinCurrent", skin_selection); } void LLFloaterPreference::refreshSkin(void* data) { - LLPanel*self = (LLPanel*)data; - sSkin = gSavedSettings.getString("SkinCurrent"); - self->getChild("skin_selection", true)->setValue(sSkin); + LLPanel*self = (LLPanel*)data; + sSkin = gSavedSettings.getString("SkinCurrent"); + self->getChild("skin_selection", true)->setValue(sSkin); } void LLFloaterPreference::buildPopupLists() { - LLScrollListCtrl& disabled_popups = - getChildRef("disabled_popups"); - LLScrollListCtrl& enabled_popups = - getChildRef("enabled_popups"); - - disabled_popups.deleteAllItems(); - enabled_popups.deleteAllItems(); - - for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); - iter != LLNotifications::instance().templatesEnd(); - ++iter) - { - LLNotificationTemplatePtr templatep = iter->second; - LLNotificationFormPtr formp = templatep->mForm; - - LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); - if (ignore <= LLNotificationForm::IGNORE_NO) - continue; - - LLSD row; - row["columns"][0]["value"] = formp->getIgnoreMessage(); - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - row["columns"][0]["width"] = 400; - - LLScrollListItem* item = NULL; - - bool show_popup = !formp->getIgnored(); - if (!show_popup) - { - if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName); - if (!last_response.isUndefined()) - { - for (LLSD::map_const_iterator it = last_response.beginMap(); - it != last_response.endMap(); - ++it) - { - if (it->second.asBoolean()) - { - row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString(); - row["columns"][1]["font"] = "SANSSERIF_SMALL"; - row["columns"][1]["width"] = 360; - break; - } - } - } - } - item = disabled_popups.addElement(row); - } - else - { - item = enabled_popups.addElement(row); - } - - if (item) - { - item->setUserdata((void*)&iter->first); - } - } + LLScrollListCtrl& disabled_popups = + getChildRef("disabled_popups"); + LLScrollListCtrl& enabled_popups = + getChildRef("enabled_popups"); + + disabled_popups.deleteAllItems(); + enabled_popups.deleteAllItems(); + + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + LLNotificationTemplatePtr templatep = iter->second; + LLNotificationFormPtr formp = templatep->mForm; + + LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); + if (ignore <= LLNotificationForm::IGNORE_NO) + continue; + + LLSD row; + row["columns"][0]["value"] = formp->getIgnoreMessage(); + row["columns"][0]["font"] = "SANSSERIF_SMALL"; + row["columns"][0]["width"] = 400; + + LLScrollListItem* item = NULL; + + bool show_popup = !formp->getIgnored(); + if (!show_popup) + { + if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName); + if (!last_response.isUndefined()) + { + for (LLSD::map_const_iterator it = last_response.beginMap(); + it != last_response.endMap(); + ++it) + { + if (it->second.asBoolean()) + { + row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString(); + row["columns"][1]["font"] = "SANSSERIF_SMALL"; + row["columns"][1]["width"] = 360; + break; + } + } + } + } + item = disabled_popups.addElement(row); + } + else + { + item = enabled_popups.addElement(row); + } + + if (item) + { + item->setUserdata((void*)&iter->first); + } + } } void LLFloaterPreference::refreshEnabledState() { - LLCheckBoxCtrl* ctrl_pbr = getChild("UsePBRShaders"); + LLCheckBoxCtrl* ctrl_pbr = getChild("UsePBRShaders"); //PBR ctrl_pbr->setEnabled(TRUE); - // Cannot have floater active until caps have been received - getChild("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); + // Cannot have floater active until caps have been received + getChild("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); - getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); + getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); } void LLAvatarComplexityControls::setIndirectControls() { - /* - * We have controls that have an indirect relationship between the control - * values and adjacent text and the underlying setting they influence. - * In each case, the control and its associated setting are named Indirect - * This method interrogates the controlled setting and establishes the - * appropriate value for the indirect control. It must be called whenever the - * underlying setting may have changed other than through the indirect control, - * such as when the 'Reset all to recommended settings' button is used... - */ - setIndirectMaxNonImpostors(); - setIndirectMaxArc(); + /* + * We have controls that have an indirect relationship between the control + * values and adjacent text and the underlying setting they influence. + * In each case, the control and its associated setting are named Indirect + * This method interrogates the controlled setting and establishes the + * appropriate value for the indirect control. It must be called whenever the + * underlying setting may have changed other than through the indirect control, + * such as when the 'Reset all to recommended settings' button is used... + */ + setIndirectMaxNonImpostors(); + setIndirectMaxArc(); } // static void LLAvatarComplexityControls::setIndirectMaxNonImpostors() { - U32 max_non_impostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); - // for this one, we just need to make zero, which means off, the max value of the slider - U32 indirect_max_non_impostors = (0 == max_non_impostors) ? LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER : max_non_impostors; - gSavedSettings.setU32("IndirectMaxNonImpostors", indirect_max_non_impostors); + U32 max_non_impostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); + // for this one, we just need to make zero, which means off, the max value of the slider + U32 indirect_max_non_impostors = (0 == max_non_impostors) ? LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER : max_non_impostors; + gSavedSettings.setU32("IndirectMaxNonImpostors", indirect_max_non_impostors); } void LLAvatarComplexityControls::setIndirectMaxArc() { - U32 max_arc = gSavedSettings.getU32("RenderAvatarMaxComplexity"); - U32 indirect_max_arc; - if (0 == max_arc) - { - // the off position is all the way to the right, so set to control max - indirect_max_arc = INDIRECT_MAX_ARC_OFF; - } - else - { - // This is the inverse of the calculation in updateMaxComplexity - indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT; - } - gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); + U32 max_arc = gSavedSettings.getU32("RenderAvatarMaxComplexity"); + U32 indirect_max_arc; + if (0 == max_arc) + { + // the off position is all the way to the right, so set to control max + indirect_max_arc = INDIRECT_MAX_ARC_OFF; + } + else + { + // This is the inverse of the calculation in updateMaxComplexity + indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT; + } + gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); } void LLFloaterPreference::refresh() { - LLPanel::refresh(); + LLPanel::refresh(); LLAvatarComplexityControls::setText( gSavedSettings.getU32("RenderAvatarMaxComplexity"), getChild("IndirectMaxComplexityText", true)); - refreshEnabledState(); - LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - if (advanced) - { - advanced->refresh(); - } + refreshEnabledState(); + LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); + if (advanced) + { + advanced->refresh(); + } updateClickActionViews(); } void LLFloaterPreference::onCommitWindowedMode() { - refresh(); + refresh(); } void LLFloaterPreference::onChangeQuality(const LLSD& data) { - U32 level = (U32)(data.asReal()); - LLFeatureManager::getInstance()->setGraphicsLevel(level, true); - refreshEnabledGraphics(); - refresh(); + U32 level = (U32)(data.asReal()); + LLFeatureManager::getInstance()->setGraphicsLevel(level, true); + refreshEnabledGraphics(); + refresh(); } void LLFloaterPreference::onClickSetSounds() { - // Disable Enable gesture sounds checkbox if the master sound is disabled - // or if sound effects are disabled. - getChild("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); + // Disable Enable gesture sounds checkbox if the master sound is disabled + // or if sound effects are disabled. + getChild("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } void LLFloaterPreference::onClickEnablePopup() -{ - LLScrollListCtrl& disabled_popups = getChildRef("disabled_popups"); - - std::vector items = disabled_popups.getAllSelected(); - std::vector::iterator itor; - for (itor = items.begin(); itor != items.end(); ++itor) - { - LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); - //gSavedSettings.setWarning(templatep->mName, TRUE); - std::string notification_name = templatep->mName; - LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE); - } - - buildPopupLists(); +{ + LLScrollListCtrl& disabled_popups = getChildRef("disabled_popups"); + + std::vector items = disabled_popups.getAllSelected(); + std::vector::iterator itor; + for (itor = items.begin(); itor != items.end(); ++itor) + { + LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); + //gSavedSettings.setWarning(templatep->mName, TRUE); + std::string notification_name = templatep->mName; + LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE); + } + + buildPopupLists(); if (!mFilterEdit->getText().empty()) { filterIgnorableNotifications(); @@ -1337,18 +1337,18 @@ void LLFloaterPreference::onClickEnablePopup() } void LLFloaterPreference::onClickDisablePopup() -{ - LLScrollListCtrl& enabled_popups = getChildRef("enabled_popups"); - - std::vector items = enabled_popups.getAllSelected(); - std::vector::iterator itor; - for (itor = items.begin(); itor != items.end(); ++itor) - { - LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); - templatep->mForm->setIgnored(true); - } - - buildPopupLists(); +{ + LLScrollListCtrl& enabled_popups = getChildRef("enabled_popups"); + + std::vector items = enabled_popups.getAllSelected(); + std::vector::iterator itor; + for (itor = items.begin(); itor != items.end(); ++itor) + { + LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata())); + templatep->mForm->setIgnored(true); + } + + buildPopupLists(); if (!mFilterEdit->getText().empty()) { filterIgnorableNotifications(); @@ -1357,191 +1357,191 @@ void LLFloaterPreference::onClickDisablePopup() void LLFloaterPreference::resetAllIgnored() { - for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); - iter != LLNotifications::instance().templatesEnd(); - ++iter) - { - if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) - { - iter->second->mForm->setIgnored(false); - } - } + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) + { + iter->second->mForm->setIgnored(false); + } + } } void LLFloaterPreference::setAllIgnored() { - for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); - iter != LLNotifications::instance().templatesEnd(); - ++iter) - { - if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) - { - iter->second->mForm->setIgnored(true); - } - } + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) + { + iter->second->mForm->setIgnored(true); + } + } } void LLFloaterPreference::onClickLogPath() { - std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - mPriorInstantMessageLogPath.clear(); - + std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + mPriorInstantMessageLogPath.clear(); + - (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeLogPath, this, _1, _2), proposed_name))->getFile(); + (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeLogPath, this, _1, _2), proposed_name))->getFile(); } void LLFloaterPreference::changeLogPath(const std::vector& filenames, std::string proposed_name) { - //Path changed - if (proposed_name != filenames[0]) - { - gSavedPerAccountSettings.setString("InstantMessageLogPath", filenames[0]); - mPriorInstantMessageLogPath = proposed_name; + //Path changed + if (proposed_name != filenames[0]) + { + gSavedPerAccountSettings.setString("InstantMessageLogPath", filenames[0]); + mPriorInstantMessageLogPath = proposed_name; - // enable/disable 'Delete transcripts button - updateDeleteTranscriptsButton(); - } + // enable/disable 'Delete transcripts button + updateDeleteTranscriptsButton(); + } } bool LLFloaterPreference::moveTranscriptsAndLog() { - std::string instantMessageLogPath(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - std::string chatLogPath = gDirUtilp->add(instantMessageLogPath, gDirUtilp->getUserName()); - - bool madeDirectory = false; - - //Does the directory really exist, if not then make it - if(!LLFile::isdir(chatLogPath)) - { - //mkdir success is defined as zero - if(LLFile::mkdir(chatLogPath) != 0) - { - return false; - } - madeDirectory = true; - } - - std::string originalConversationLogDir = LLConversationLog::instance().getFileName(); - std::string targetConversationLogDir = gDirUtilp->add(chatLogPath, "conversation.log"); - //Try to move the conversation log - if(!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir)) - { - //Couldn't move the log and created a new directory so remove the new directory - if(madeDirectory) - { - LLFile::rmdir(chatLogPath); - } - return false; - } - - //Attempt to move transcripts - std::vector listOfTranscripts; - std::vector listOfFilesMoved; - - LLLogChat::getListOfTranscriptFiles(listOfTranscripts); - - if(!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(), - instantMessageLogPath, - listOfTranscripts, - listOfFilesMoved)) - { - //Couldn't move all the transcripts so restore those that moved back to their old location - LLLogChat::moveTranscripts(instantMessageLogPath, - gDirUtilp->getChatLogsDir(), - listOfFilesMoved); - - //Move the conversation log back - LLConversationLog::instance().moveLog(targetConversationLogDir, originalConversationLogDir); - - if(madeDirectory) - { - LLFile::rmdir(chatLogPath); - } - - return false; - } - - gDirUtilp->setChatLogsDir(instantMessageLogPath); - gDirUtilp->updatePerAccountChatLogsDir(); - - return true; + std::string instantMessageLogPath(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + std::string chatLogPath = gDirUtilp->add(instantMessageLogPath, gDirUtilp->getUserName()); + + bool madeDirectory = false; + + //Does the directory really exist, if not then make it + if(!LLFile::isdir(chatLogPath)) + { + //mkdir success is defined as zero + if(LLFile::mkdir(chatLogPath) != 0) + { + return false; + } + madeDirectory = true; + } + + std::string originalConversationLogDir = LLConversationLog::instance().getFileName(); + std::string targetConversationLogDir = gDirUtilp->add(chatLogPath, "conversation.log"); + //Try to move the conversation log + if(!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir)) + { + //Couldn't move the log and created a new directory so remove the new directory + if(madeDirectory) + { + LLFile::rmdir(chatLogPath); + } + return false; + } + + //Attempt to move transcripts + std::vector listOfTranscripts; + std::vector listOfFilesMoved; + + LLLogChat::getListOfTranscriptFiles(listOfTranscripts); + + if(!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(), + instantMessageLogPath, + listOfTranscripts, + listOfFilesMoved)) + { + //Couldn't move all the transcripts so restore those that moved back to their old location + LLLogChat::moveTranscripts(instantMessageLogPath, + gDirUtilp->getChatLogsDir(), + listOfFilesMoved); + + //Move the conversation log back + LLConversationLog::instance().moveLog(targetConversationLogDir, originalConversationLogDir); + + if(madeDirectory) + { + LLFile::rmdir(chatLogPath); + } + + return false; + } + + gDirUtilp->setChatLogsDir(instantMessageLogPath); + gDirUtilp->updatePerAccountChatLogsDir(); + + return true; } void LLFloaterPreference::setPersonalInfo(const std::string& visibility) { - mGotPersonalInfo = true; - mDirectoryVisibility = visibility; - - if (visibility == VISIBILITY_DEFAULT) - { - mOriginalHideOnlineStatus = false; - getChildView("online_visibility")->setEnabled(TRUE); - } - else if (visibility == VISIBILITY_HIDDEN) - { - mOriginalHideOnlineStatus = true; - getChildView("online_visibility")->setEnabled(TRUE); - } - else - { - mOriginalHideOnlineStatus = true; - } - - getChild("online_searchresults")->setEnabled(TRUE); - getChildView("friends_online_notify_checkbox")->setEnabled(TRUE); - getChild("online_visibility")->setValue(mOriginalHideOnlineStatus); - getChild("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility); - - getChildView("favorites_on_login_check")->setEnabled(TRUE); - getChildView("log_path_button")->setEnabled(TRUE); - getChildView("chat_font_size")->setEnabled(TRUE); - getChildView("conversation_log_combo")->setEnabled(TRUE); - getChild("voice_call_friends_only_check")->setEnabled(TRUE); - getChild("voice_call_friends_only_check")->setValue(gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly")); + mGotPersonalInfo = true; + mDirectoryVisibility = visibility; + + if (visibility == VISIBILITY_DEFAULT) + { + mOriginalHideOnlineStatus = false; + getChildView("online_visibility")->setEnabled(TRUE); + } + else if (visibility == VISIBILITY_HIDDEN) + { + mOriginalHideOnlineStatus = true; + getChildView("online_visibility")->setEnabled(TRUE); + } + else + { + mOriginalHideOnlineStatus = true; + } + + getChild("online_searchresults")->setEnabled(TRUE); + getChildView("friends_online_notify_checkbox")->setEnabled(TRUE); + getChild("online_visibility")->setValue(mOriginalHideOnlineStatus); + getChild("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility); + + getChildView("favorites_on_login_check")->setEnabled(TRUE); + getChildView("log_path_button")->setEnabled(TRUE); + getChildView("chat_font_size")->setEnabled(TRUE); + getChildView("conversation_log_combo")->setEnabled(TRUE); + getChild("voice_call_friends_only_check")->setEnabled(TRUE); + getChild("voice_call_friends_only_check")->setValue(gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly")); } void LLFloaterPreference::refreshUI() { - refresh(); + refresh(); } -void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) -{ - // Called when the IndirectMaxComplexity control changes - // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity - U32 indirect_value = slider->getValue().asInteger(); - U32 max_arc; - - if (INDIRECT_MAX_ARC_OFF == indirect_value) - { - // The 'off' position is when the slider is all the way to the right, - // which is a value of INDIRECT_MAX_ARC_OFF, - // so it is necessary to set max_arc to 0 disable muted avatars. - max_arc = 0; - } - else - { - // if this is changed, the inverse calculation in setIndirectMaxArc - // must be changed to match - max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT)))); - } - - gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); - setText(max_arc, value_label, short_val); +void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) +{ + // Called when the IndirectMaxComplexity control changes + // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity + U32 indirect_value = slider->getValue().asInteger(); + U32 max_arc; + + if (INDIRECT_MAX_ARC_OFF == indirect_value) + { + // The 'off' position is when the slider is all the way to the right, + // which is a value of INDIRECT_MAX_ARC_OFF, + // so it is necessary to set max_arc to 0 disable muted avatars. + max_arc = 0; + } + else + { + // if this is changed, the inverse calculation in setIndirectMaxArc + // must be changed to match + max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT)))); + } + + gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); + setText(max_arc, value_label, short_val); } void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool short_val) { - if (0 == value) - { - text_box->setText(LLTrans::getString("no_limit")); - } - else - { + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { std::string text_value = short_val ? llformat("%d", value / 1000) : llformat("%d", value); text_box->setText(text_value); - } + } } void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) @@ -1563,7 +1563,7 @@ void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_bo void LLFloaterPreference::updateMaxComplexity() { - // Called when the IndirectMaxComplexity control changes + // Called when the IndirectMaxComplexity control changes LLAvatarComplexityControls::updateMax( getChild("IndirectMaxComplexity"), getChild("IndirectMaxComplexityText")); @@ -1616,16 +1616,16 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map void LLFloaterPreference::onChangeMaturity() { - U8 sim_access = gSavedSettings.getU32("PreferredMaturity"); + U8 sim_access = gSavedSettings.getU32("PreferredMaturity"); - getChild("rating_icon_general")->setVisible(sim_access == SIM_ACCESS_PG - || sim_access == SIM_ACCESS_MATURE - || sim_access == SIM_ACCESS_ADULT); + getChild("rating_icon_general")->setVisible(sim_access == SIM_ACCESS_PG + || sim_access == SIM_ACCESS_MATURE + || sim_access == SIM_ACCESS_ADULT); - getChild("rating_icon_moderate")->setVisible(sim_access == SIM_ACCESS_MATURE - || sim_access == SIM_ACCESS_ADULT); + getChild("rating_icon_moderate")->setVisible(sim_access == SIM_ACCESS_MATURE + || sim_access == SIM_ACCESS_ADULT); - getChild("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT); + getChild("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT); } std::string get_category_path(LLFolderType::EType cat_type) @@ -1678,23 +1678,23 @@ void LLFloaterPreference::onChangeAnimationFolder() // but the UI for this will still be enabled void LLFloaterPreference::onClickBlockList() { - LLFloaterSidePanelContainer::showPanel("people", "panel_people", - LLSD().with("people_panel_tab_name", "blocked_panel")); + LLFloaterSidePanelContainer::showPanel("people", "panel_people", + LLSD().with("people_panel_tab_name", "blocked_panel")); } void LLFloaterPreference::onClickProxySettings() { - LLFloaterReg::showInstance("prefs_proxy"); + LLFloaterReg::showInstance("prefs_proxy"); } void LLFloaterPreference::onClickTranslationSettings() { - LLFloaterReg::showInstance("prefs_translation"); + LLFloaterReg::showInstance("prefs_translation"); } void LLFloaterPreference::onClickAutoReplace() { - LLFloaterReg::showInstance("prefs_autoreplace"); + LLFloaterReg::showInstance("prefs_autoreplace"); } void LLFloaterPreference::onClickSpellChecker() @@ -1718,19 +1718,19 @@ void LLFloaterPreference::onClickAutoAdjustments() void LLFloaterPreference::onClickAdvanced() { - LLFloaterReg::showInstance("prefs_graphics_advanced"); + LLFloaterReg::showInstance("prefs_graphics_advanced"); - LLTabContainer* tabcontainer = getChild("pref core"); - for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); - iter != tabcontainer->getChildList()->end(); ++iter) - { - LLView* view = *iter; - LLPanelPreferenceGraphics* panel = dynamic_cast(view); - if (panel) - { - panel->resetDirtyChilds(); - } - } + LLTabContainer* tabcontainer = getChild("pref core"); + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreferenceGraphics* panel = dynamic_cast(view); + if (panel) + { + panel->resetDirtyChilds(); + } + } } void LLFloaterPreference::onClickActionChange() @@ -1756,7 +1756,7 @@ void LLFloaterPreference::onAtmosShaderChange() void LLFloaterPreference::onClickPermsDefault() { - LLFloaterReg::showInstance("perms_default"); + LLFloaterReg::showInstance("perms_default"); } void LLFloaterPreference::onClickRememberedUsernames() @@ -1766,29 +1766,29 @@ void LLFloaterPreference::onClickRememberedUsernames() void LLFloaterPreference::onDeleteTranscripts() { - LLSD args; - args["FOLDER"] = gDirUtilp->getUserName(); + LLSD args; + args["FOLDER"] = gDirUtilp->getUserName(); - LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", args, LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); + LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", args, LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); } void LLFloaterPreference::onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response) { - if (0 == LLNotificationsUtil::getSelectedOption(notification, response)) - { - LLLogChat::deleteTranscripts(); - updateDeleteTranscriptsButton(); - } + if (0 == LLNotificationsUtil::getSelectedOption(notification, response)) + { + LLLogChat::deleteTranscripts(); + updateDeleteTranscriptsButton(); + } } void LLFloaterPreference::onLogChatHistorySaved() { - LLButton * delete_transcripts_buttonp = getChild("delete_transcripts"); + LLButton * delete_transcripts_buttonp = getChild("delete_transcripts"); - if (!delete_transcripts_buttonp->getEnabled()) - { - delete_transcripts_buttonp->setEnabled(true); - } + if (!delete_transcripts_buttonp->getEnabled()) + { + delete_transcripts_buttonp->setEnabled(true); + } } void LLFloaterPreference::updateClickActionControls() @@ -1816,13 +1816,13 @@ void LLFloaterPreference::updateClickActionControls() KEY_NONE, MASK_NONE, single_clk_action == 1); - + panel->setKeyBind("walk_to", EMouseClickType::CLICK_DOUBLELEFT, KEY_NONE, MASK_NONE, double_clk_action == 1); - + panel->setKeyBind("teleport_to", EMouseClickType::CLICK_DOUBLELEFT, KEY_NONE, @@ -1867,8 +1867,8 @@ void LLFloaterPreference::updateClickActionViews() } } - getChild("single_click_action_combo")->setValue((int)click_to_walk); - getChild("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); + getChild("single_click_action_combo")->setValue((int)click_to_walk); + getChild("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); } void LLFloaterPreference::updateSearchableItems() @@ -1878,62 +1878,62 @@ void LLFloaterPreference::updateSearchableItems() void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param) { - LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); + LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); } void LLFloaterPreference::getUIColor(LLUICtrl* ctrl, const LLSD& param) { - LLColorSwatchCtrl* color_swatch = (LLColorSwatchCtrl*) ctrl; - color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString())); + LLColorSwatchCtrl* color_swatch = (LLColorSwatchCtrl*) ctrl; + color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString())); } void LLFloaterPreference::setCacheLocation(const LLStringExplicit& location) { - LLUICtrl* cache_location_editor = getChild("cache_location"); - cache_location_editor->setValue(location); - cache_location_editor->setToolTip(location); + LLUICtrl* cache_location_editor = getChild("cache_location"); + cache_location_editor->setValue(location); + cache_location_editor->setToolTip(location); } void LLFloaterPreference::selectPanel(const LLSD& name) { - LLTabContainer * tab_containerp = getChild("pref core"); - LLPanel * panel = tab_containerp->getPanelByName(name); - if (NULL != panel) - { - tab_containerp->selectTabPanel(panel); - } + LLTabContainer * tab_containerp = getChild("pref core"); + LLPanel * panel = tab_containerp->getPanelByName(name); + if (NULL != panel) + { + tab_containerp->selectTabPanel(panel); + } } void LLFloaterPreference::selectPrivacyPanel() { - selectPanel("im"); + selectPanel("im"); } void LLFloaterPreference::selectChatPanel() { - selectPanel("chat"); + selectPanel("chat"); } void LLFloaterPreference::changed() { - getChild("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0); + getChild("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0); - // set 'enable' property for 'Delete transcripts...' button - updateDeleteTranscriptsButton(); + // set 'enable' property for 'Delete transcripts...' button + updateDeleteTranscriptsButton(); } void LLFloaterPreference::saveGraphicsPreset(std::string& preset) { - mSavedGraphicsPreset = preset; + mSavedGraphicsPreset = preset; } //------------------------------Updater--------------------------------------- static bool handleBandwidthChanged(const LLSD& newvalue) { - gViewerThrottle.setMaxBandwidth((F32) newvalue.asReal()); - return true; + gViewerThrottle.setMaxBandwidth((F32) newvalue.asReal()); + return true; } class LLPanelPreference::Updater : public LLEventTimer @@ -1941,37 +1941,37 @@ class LLPanelPreference::Updater : public LLEventTimer public: - typedef boost::function callback_t; + typedef boost::function callback_t; - Updater(callback_t cb, F32 period) - :LLEventTimer(period), - mCallback(cb) - { - stop(); - } + Updater(callback_t cb, F32 period) + :LLEventTimer(period), + mCallback(cb) + { + stop(); + } - virtual ~Updater(){} + virtual ~Updater(){} - void update(const LLSD& new_value) - { - mNewValue = new_value; - start(); - } + void update(const LLSD& new_value) + { + mNewValue = new_value; + start(); + } protected: - bool tick() override - { - mCallback(mNewValue); - stop(); + bool tick() override + { + mCallback(mNewValue); + stop(); - return false; - } + return false; + } private: - LLSD mNewValue; - callback_t mCallback; + LLSD mNewValue; + callback_t mCallback; }; //---------------------------------------------------------------------------- static LLPanelInjector t_places("panel_preference"); @@ -1979,160 +1979,160 @@ LLPanelPreference::LLPanelPreference() : LLPanel(), mBandWidthUpdater(NULL) { - mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2)); - mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1)); - mCommitCallbackRegistrar.add("Pref.PrefDelete", boost::bind(&LLPanelPreference::deletePreset, this, _2)); - mCommitCallbackRegistrar.add("Pref.PrefSave", boost::bind(&LLPanelPreference::savePreset, this, _2)); - mCommitCallbackRegistrar.add("Pref.PrefLoad", boost::bind(&LLPanelPreference::loadPreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2)); + mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1)); + mCommitCallbackRegistrar.add("Pref.PrefDelete", boost::bind(&LLPanelPreference::deletePreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.PrefSave", boost::bind(&LLPanelPreference::savePreset, this, _2)); + mCommitCallbackRegistrar.add("Pref.PrefLoad", boost::bind(&LLPanelPreference::loadPreset, this, _2)); } //virtual BOOL LLPanelPreference::postBuild() { - ////////////////////// PanelGeneral /////////////////// - if (hasChild("display_names_check", TRUE)) - { - BOOL use_people_api = gSavedSettings.getBOOL("UsePeopleAPI"); - LLCheckBoxCtrl* ctrl_display_name = getChild("display_names_check"); - ctrl_display_name->setEnabled(use_people_api); - if (!use_people_api) - { - ctrl_display_name->setValue(FALSE); - } - } - - ////////////////////// PanelVoice /////////////////// - if (hasChild("voice_unavailable", TRUE)) - { - BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice"); - getChildView("voice_unavailable")->setVisible( voice_disabled); - getChildView("enable_voice_check")->setVisible( !voice_disabled); - } - - //////////////////////PanelSkins /////////////////// - - if (hasChild("skin_selection", TRUE)) - { - LLFloaterPreference::refreshSkin(this); - - // if skin is set to a skin that no longer exists (silver) set back to default - if (getChild("skin_selection")->getSelectedIndex() < 0) - { - gSavedSettings.setString("SkinCurrent", "default"); - LLFloaterPreference::refreshSkin(this); - } - - } - - //////////////////////PanelPrivacy /////////////////// - if (hasChild("media_enabled", TRUE)) - { - bool media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); - - getChild("media_enabled")->set(media_enabled); - getChild("autoplay_enabled")->setEnabled(media_enabled); - } - if (hasChild("music_enabled", TRUE)) - { - getChild("music_enabled")->set(gSavedSettings.getBOOL("AudioStreamingMusic")); - } - if (hasChild("voice_call_friends_only_check", TRUE)) - { - getChild("voice_call_friends_only_check")->setCommitCallback(boost::bind(&showFriendsOnlyWarning, _1, _2)); - } - if (hasChild("allow_multiple_viewer_check", TRUE)) - { - getChild("allow_multiple_viewer_check")->setCommitCallback(boost::bind(&showMultipleViewersWarning, _1, _2)); - } - if (hasChild("favorites_on_login_check", TRUE)) - { - getChild("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2)); - bool show_favorites_at_login = LLPanelLogin::getShowFavorites(); - getChild("favorites_on_login_check")->setValue(show_favorites_at_login); - } - if (hasChild("mute_chb_label", TRUE)) - { - getChild("mute_chb_label")->setShowCursorHand(false); - getChild("mute_chb_label")->setSoundFlags(LLView::MOUSE_UP); - getChild("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); - } - - //////////////////////PanelSetup /////////////////// - if (hasChild("max_bandwidth", TRUE)) - { - mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT); - gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2)); - } + ////////////////////// PanelGeneral /////////////////// + if (hasChild("display_names_check", TRUE)) + { + BOOL use_people_api = gSavedSettings.getBOOL("UsePeopleAPI"); + LLCheckBoxCtrl* ctrl_display_name = getChild("display_names_check"); + ctrl_display_name->setEnabled(use_people_api); + if (!use_people_api) + { + ctrl_display_name->setValue(FALSE); + } + } + + ////////////////////// PanelVoice /////////////////// + if (hasChild("voice_unavailable", TRUE)) + { + BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice"); + getChildView("voice_unavailable")->setVisible( voice_disabled); + getChildView("enable_voice_check")->setVisible( !voice_disabled); + } + + //////////////////////PanelSkins /////////////////// + + if (hasChild("skin_selection", TRUE)) + { + LLFloaterPreference::refreshSkin(this); + + // if skin is set to a skin that no longer exists (silver) set back to default + if (getChild("skin_selection")->getSelectedIndex() < 0) + { + gSavedSettings.setString("SkinCurrent", "default"); + LLFloaterPreference::refreshSkin(this); + } + + } + + //////////////////////PanelPrivacy /////////////////// + if (hasChild("media_enabled", TRUE)) + { + bool media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); + + getChild("media_enabled")->set(media_enabled); + getChild("autoplay_enabled")->setEnabled(media_enabled); + } + if (hasChild("music_enabled", TRUE)) + { + getChild("music_enabled")->set(gSavedSettings.getBOOL("AudioStreamingMusic")); + } + if (hasChild("voice_call_friends_only_check", TRUE)) + { + getChild("voice_call_friends_only_check")->setCommitCallback(boost::bind(&showFriendsOnlyWarning, _1, _2)); + } + if (hasChild("allow_multiple_viewer_check", TRUE)) + { + getChild("allow_multiple_viewer_check")->setCommitCallback(boost::bind(&showMultipleViewersWarning, _1, _2)); + } + if (hasChild("favorites_on_login_check", TRUE)) + { + getChild("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2)); + bool show_favorites_at_login = LLPanelLogin::getShowFavorites(); + getChild("favorites_on_login_check")->setValue(show_favorites_at_login); + } + if (hasChild("mute_chb_label", TRUE)) + { + getChild("mute_chb_label")->setShowCursorHand(false); + getChild("mute_chb_label")->setSoundFlags(LLView::MOUSE_UP); + getChild("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); + } + + //////////////////////PanelSetup /////////////////// + if (hasChild("max_bandwidth", TRUE)) + { + mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT); + gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2)); + } #ifdef EXTERNAL_TOS - LLRadioGroup* ext_browser_settings = getChild("preferred_browser_behavior"); - if (ext_browser_settings) - { - // turn off ability to set external/internal browser - ext_browser_settings->setSelectedByValue(LLWeb::BROWSER_EXTERNAL_ONLY, true); - ext_browser_settings->setEnabled(false); - } + LLRadioGroup* ext_browser_settings = getChild("preferred_browser_behavior"); + if (ext_browser_settings) + { + // turn off ability to set external/internal browser + ext_browser_settings->setSelectedByValue(LLWeb::BROWSER_EXTERNAL_ONLY, true); + ext_browser_settings->setEnabled(false); + } #endif - apply(); - return true; + apply(); + return true; } LLPanelPreference::~LLPanelPreference() { - if (mBandWidthUpdater) - { - delete mBandWidthUpdater; - } + if (mBandWidthUpdater) + { + delete mBandWidthUpdater; + } } void LLPanelPreference::apply() { - // no-op + // no-op } void LLPanelPreference::saveSettings() { - LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - - // Save the value of all controls in the hierarchy - mSavedValues.clear(); - std::list view_stack; - view_stack.push_back(this); - if (advanced) - { - view_stack.push_back(advanced); - } - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLColorSwatchCtrl* color_swatch = dynamic_cast(curview); - if (color_swatch) - { - mSavedColors[color_swatch->getName()] = color_swatch->get(); - } - else - { - LLUICtrl* ctrl = dynamic_cast(curview); - if (ctrl) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - mSavedValues[control] = control->getValue(); - } - } - } - - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } + LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); + + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list view_stack; + view_stack.push_back(this); + if (advanced) + { + view_stack.push_back(advanced); + } + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLColorSwatchCtrl* color_swatch = dynamic_cast(curview); + if (color_swatch) + { + mSavedColors[color_swatch->getName()] = color_swatch->get(); + } + else + { + LLUICtrl* ctrl = dynamic_cast(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + mSavedValues[control] = control->getValue(); + } + } + } + + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } if (LLStartUp::getStartupState() == STATE_STARTED) { @@ -2154,104 +2154,104 @@ void LLPanelPreference::showMultipleViewersWarning(LLUICtrl* checkbox, const LLS void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& value) { - if (checkbox) - { - gSavedPerAccountSettings.setBOOL("VoiceCallsFriendsOnly", checkbox->getValue().asBoolean()); - if (checkbox->getValue()) - { - LLNotificationsUtil::add("FriendsAndGroupsOnly"); - } - } + if (checkbox) + { + gSavedPerAccountSettings.setBOOL("VoiceCallsFriendsOnly", checkbox->getValue().asBoolean()); + if (checkbox->getValue()) + { + LLNotificationsUtil::add("FriendsAndGroupsOnly"); + } + } } void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value) { - if (checkbox) - { - LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean()); - if(checkbox->getValue()) - { - LLNotificationsUtil::add("FavoritesOnLogin"); - } - } + if (checkbox) + { + LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean()); + if(checkbox->getValue()) + { + LLNotificationsUtil::add("FavoritesOnLogin"); + } + } } void LLPanelPreference::toggleMuteWhenMinimized() { - std::string mute("MuteWhenMinimized"); - gSavedSettings.setBOOL(mute, !gSavedSettings.getBOOL(mute)); - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->getChild("mute_when_minimized")->setBtnFocus(); - } + std::string mute("MuteWhenMinimized"); + gSavedSettings.setBOOL(mute, !gSavedSettings.getBOOL(mute)); + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->getChild("mute_when_minimized")->setBtnFocus(); + } } void LLPanelPreference::cancel() { - for (control_values_map_t::iterator iter = mSavedValues.begin(); - iter != mSavedValues.end(); ++iter) - { - LLControlVariable* control = iter->first; - LLSD ctrl_value = iter->second; + for (control_values_map_t::iterator iter = mSavedValues.begin(); + iter != mSavedValues.end(); ++iter) + { + LLControlVariable* control = iter->first; + LLSD ctrl_value = iter->second; - if((control->getName() == "InstantMessageLogPath") && (ctrl_value.asString() == "")) - { - continue; - } + if((control->getName() == "InstantMessageLogPath") && (ctrl_value.asString() == "")) + { + continue; + } - control->set(ctrl_value); - } + control->set(ctrl_value); + } - for (string_color_map_t::iterator iter = mSavedColors.begin(); - iter != mSavedColors.end(); ++iter) - { - LLColorSwatchCtrl* color_swatch = findChild(iter->first); - if (color_swatch) - { - color_swatch->set(iter->second); - color_swatch->onCommit(); - } - } + for (string_color_map_t::iterator iter = mSavedColors.begin(); + iter != mSavedColors.end(); ++iter) + { + LLColorSwatchCtrl* color_swatch = findChild(iter->first); + if (color_swatch) + { + color_swatch->set(iter->second); + color_swatch->onCommit(); + } + } } void LLPanelPreference::setControlFalse(const LLSD& user_data) { - std::string control_name = user_data.asString(); - LLControlVariable* control = findControl(control_name); - - if (control) - control->set(LLSD(FALSE)); + std::string control_name = user_data.asString(); + LLControlVariable* control = findControl(control_name); + + if (control) + control->set(LLSD(FALSE)); } void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) { - std::string name = ctrl->getName(); + std::string name = ctrl->getName(); - // Disable "Allow Media to auto play" only when both - // "Streaming Music" and "Media" are unchecked. STORM-513. - if ((name == "enable_music") || (name == "enable_media")) - { - bool music_enabled = getChild("enable_music")->get(); - bool media_enabled = getChild("enable_media")->get(); + // Disable "Allow Media to auto play" only when both + // "Streaming Music" and "Media" are unchecked. STORM-513. + if ((name == "enable_music") || (name == "enable_media")) + { + bool music_enabled = getChild("enable_music")->get(); + bool media_enabled = getChild("enable_media")->get(); - getChild("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); - } + getChild("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); + } } void LLPanelPreference::deletePreset(const LLSD& user_data) { - LLFloaterReg::showInstance("delete_pref_preset", user_data.asString()); + LLFloaterReg::showInstance("delete_pref_preset", user_data.asString()); } void LLPanelPreference::savePreset(const LLSD& user_data) { - LLFloaterReg::showInstance("save_pref_preset", user_data.asString()); + LLFloaterReg::showInstance("save_pref_preset", user_data.asString()); } void LLPanelPreference::loadPreset(const LLSD& user_data) { - LLFloaterReg::showInstance("load_pref_preset", user_data.asString()); + LLFloaterReg::showInstance("load_pref_preset", user_data.asString()); } void LLPanelPreference::setHardwareDefaults() @@ -2261,38 +2261,38 @@ void LLPanelPreference::setHardwareDefaults() class LLPanelPreferencePrivacy : public LLPanelPreference { public: - LLPanelPreferencePrivacy() - { - mAccountIndependentSettings.push_back("AutoDisengageMic"); - } - - /*virtual*/ void saveSettings() - { - LLPanelPreference::saveSettings(); - - // Don't save (=erase from the saved values map) per-account privacy settings - // if we're not logged in, otherwise they will be reset to defaults on log off. - if (LLStartUp::getStartupState() != STATE_STARTED) - { - // Erase only common settings, assuming there are no color settings on Privacy page. - for (control_values_map_t::iterator it = mSavedValues.begin(); it != mSavedValues.end(); ) - { - const std::string setting = it->first->getName(); - if (find(mAccountIndependentSettings.begin(), - mAccountIndependentSettings.end(), setting) == mAccountIndependentSettings.end()) - { - mSavedValues.erase(it++); - } - else - { - ++it; - } - } - } - } + LLPanelPreferencePrivacy() + { + mAccountIndependentSettings.push_back("AutoDisengageMic"); + } + + /*virtual*/ void saveSettings() + { + LLPanelPreference::saveSettings(); + + // Don't save (=erase from the saved values map) per-account privacy settings + // if we're not logged in, otherwise they will be reset to defaults on log off. + if (LLStartUp::getStartupState() != STATE_STARTED) + { + // Erase only common settings, assuming there are no color settings on Privacy page. + for (control_values_map_t::iterator it = mSavedValues.begin(); it != mSavedValues.end(); ) + { + const std::string setting = it->first->getName(); + if (find(mAccountIndependentSettings.begin(), + mAccountIndependentSettings.end(), setting) == mAccountIndependentSettings.end()) + { + mSavedValues.erase(it++); + } + else + { + ++it; + } + } + } + } private: - std::list mAccountIndependentSettings; + std::list mAccountIndependentSettings; }; static LLPanelInjector t_pref_graph("panel_preference_graphics"); @@ -2300,170 +2300,170 @@ static LLPanelInjector t_pref_privacy("panel_preferenc BOOL LLPanelPreferenceGraphics::postBuild() { - LLFloaterReg::showInstance("prefs_graphics_advanced"); - LLFloaterReg::hideInstance("prefs_graphics_advanced"); + LLFloaterReg::showInstance("prefs_graphics_advanced"); + LLFloaterReg::hideInstance("prefs_graphics_advanced"); - resetDirtyChilds(); - setPresetText(); + resetDirtyChilds(); + setPresetText(); - LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); + LLPresetsManager* presetsMgr = LLPresetsManager::getInstance(); presetsMgr->setPresetListChangeCallback(boost::bind(&LLPanelPreferenceGraphics::onPresetsListChange, this)); presetsMgr->createMissingDefault(PRESETS_GRAPHIC); // a no-op after the first time, but that's ok - - return LLPanelPreference::postBuild(); + + return LLPanelPreference::postBuild(); } void LLPanelPreferenceGraphics::draw() { - setPresetText(); - LLPanelPreference::draw(); + setPresetText(); + LLPanelPreference::draw(); } void LLPanelPreferenceGraphics::onPresetsListChange() { - resetDirtyChilds(); - setPresetText(); + resetDirtyChilds(); + setPresetText(); - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance && !gSavedSettings.getString("PresetGraphicActive").empty()) - { - instance->saveSettings(); //make cancel work correctly after changing the preset - } + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance && !gSavedSettings.getString("PresetGraphicActive").empty()) + { + instance->saveSettings(); //make cancel work correctly after changing the preset + } } void LLPanelPreferenceGraphics::setPresetText() { - LLTextBox* preset_text = getChild("preset_text"); + LLTextBox* preset_text = getChild("preset_text"); - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - if (!preset_graphic_active.empty() && preset_graphic_active != preset_text->getText()) - { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->saveGraphicsPreset(preset_graphic_active); - } - } + if (!preset_graphic_active.empty() && preset_graphic_active != preset_text->getText()) + { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->saveGraphicsPreset(preset_graphic_active); + } + } if (hasDirtyChilds() && !preset_graphic_active.empty()) - { - gSavedSettings.setString("PresetGraphicActive", ""); - preset_graphic_active.clear(); - // This doesn't seem to cause an infinite recursion. This trigger is needed to cause the pulldown - // panel to update. - LLPresetsManager::getInstance()->triggerChangeSignal(); - } - - if (!preset_graphic_active.empty()) - { - if (preset_graphic_active == PRESETS_DEFAULT) - { - preset_graphic_active = LLTrans::getString(PRESETS_DEFAULT); - } - preset_text->setText(preset_graphic_active); - } - else - { - preset_text->setText(LLTrans::getString("none_paren_cap")); - } - - preset_text->resetDirty(); + { + gSavedSettings.setString("PresetGraphicActive", ""); + preset_graphic_active.clear(); + // This doesn't seem to cause an infinite recursion. This trigger is needed to cause the pulldown + // panel to update. + LLPresetsManager::getInstance()->triggerChangeSignal(); + } + + if (!preset_graphic_active.empty()) + { + if (preset_graphic_active == PRESETS_DEFAULT) + { + preset_graphic_active = LLTrans::getString(PRESETS_DEFAULT); + } + preset_text->setText(preset_graphic_active); + } + else + { + preset_text->setText(LLTrans::getString("none_paren_cap")); + } + + preset_text->resetDirty(); } bool LLPanelPreferenceGraphics::hasDirtyChilds() { - LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - std::list view_stack; - view_stack.push_back(this); - if (advanced) - { - view_stack.push_back(advanced); - } - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast(curview); - if (ctrl) - { - if (ctrl->isDirty()) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - std::string control_name = control->getName(); - if (!control_name.empty()) - { - return true; - } - } - } - } - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } - - return false; + LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); + std::list view_stack; + view_stack.push_back(this); + if (advanced) + { + view_stack.push_back(advanced); + } + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast(curview); + if (ctrl) + { + if (ctrl->isDirty()) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + std::string control_name = control->getName(); + if (!control_name.empty()) + { + return true; + } + } + } + } + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } + + return false; } void LLPanelPreferenceGraphics::resetDirtyChilds() { - LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - std::list view_stack; - view_stack.push_back(this); - if (advanced) - { - view_stack.push_back(advanced); - } - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast(curview); - if (ctrl) - { - ctrl->resetDirty(); - } - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } + LLFloater* advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); + std::list view_stack; + view_stack.push_back(this); + if (advanced) + { + view_stack.push_back(advanced); + } + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast(curview); + if (ctrl) + { + ctrl->resetDirty(); + } + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } } void LLPanelPreferenceGraphics::cancel() { - LLPanelPreference::cancel(); + LLPanelPreference::cancel(); } void LLPanelPreferenceGraphics::saveSettings() { - resetDirtyChilds(); - std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); - if (preset_graphic_active.empty()) - { - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - //don't restore previous preset after closing Preferences - instance->saveGraphicsPreset(preset_graphic_active); - } - } - LLPanelPreference::saveSettings(); + resetDirtyChilds(); + std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive"); + if (preset_graphic_active.empty()) + { + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + //don't restore previous preset after closing Preferences + instance->saveGraphicsPreset(preset_graphic_active); + } + } + LLPanelPreference::saveSettings(); } void LLPanelPreferenceGraphics::setHardwareDefaults() { - resetDirtyChilds(); + resetDirtyChilds(); } //------------------------LLPanelPreferenceControls-------------------------------- @@ -3033,7 +3033,7 @@ void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes) { return; } - + if (mEditingColumn > 0) { if (all_modes) @@ -3075,12 +3075,12 @@ void LLPanelPreferenceControls::onCancelKeyBind() } LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) - : LLFloater(key), - mSocksSettingsDirty(false) + : LLFloater(key), + mSocksSettingsDirty(false) { - mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); - mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); - mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); + mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this)); + mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this)); + mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); } LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() @@ -3089,192 +3089,192 @@ LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() BOOL LLFloaterPreferenceProxy::postBuild() { - LLRadioGroup* socksAuth = getChild("socks5_auth_type"); - if (!socksAuth) - { - return FALSE; - } - if (socksAuth->getSelectedValue().asString() == "None") - { - getChild("socks5_username")->setEnabled(false); - getChild("socks5_password")->setEnabled(false); - } - else - { - // Populate the SOCKS 5 credential fields with protected values. - LLPointer socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); - getChild("socks5_username")->setValue(socks_cred->getIdentifier()["username"].asString()); - getChild("socks5_password")->setValue(socks_cred->getAuthenticator()["creds"].asString()); - } - - return TRUE; + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if (!socksAuth) + { + return FALSE; + } + if (socksAuth->getSelectedValue().asString() == "None") + { + getChild("socks5_username")->setEnabled(false); + getChild("socks5_password")->setEnabled(false); + } + else + { + // Populate the SOCKS 5 credential fields with protected values. + LLPointer socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + getChild("socks5_username")->setValue(socks_cred->getIdentifier()["username"].asString()); + getChild("socks5_password")->setValue(socks_cred->getAuthenticator()["creds"].asString()); + } + + return TRUE; } void LLFloaterPreferenceProxy::onOpen(const LLSD& key) { - saveSettings(); + saveSettings(); } void LLFloaterPreferenceProxy::onClose(bool app_quitting) { - if(app_quitting) - { - cancel(); - } + if(app_quitting) + { + cancel(); + } - if (mSocksSettingsDirty) - { + if (mSocksSettingsDirty) + { - // If the user plays with the Socks proxy settings after login, it's only fair we let them know - // it will not be updated until next restart. - if (LLStartUp::getStartupState()>STATE_LOGIN_WAIT) - { - LLNotifications::instance().add("ChangeProxySettings", LLSD(), LLSD()); - mSocksSettingsDirty = false; // we have notified the user now be quiet again - } - } + // If the user plays with the Socks proxy settings after login, it's only fair we let them know + // it will not be updated until next restart. + if (LLStartUp::getStartupState()>STATE_LOGIN_WAIT) + { + LLNotifications::instance().add("ChangeProxySettings", LLSD(), LLSD()); + mSocksSettingsDirty = false; // we have notified the user now be quiet again + } + } } void LLFloaterPreferenceProxy::saveSettings() { - // Save the value of all controls in the hierarchy - mSavedValues.clear(); - std::list view_stack; - view_stack.push_back(this); - while(!view_stack.empty()) - { - // Process view on top of the stack - LLView* curview = view_stack.front(); - view_stack.pop_front(); - - LLUICtrl* ctrl = dynamic_cast(curview); - if (ctrl) - { - LLControlVariable* control = ctrl->getControlVariable(); - if (control) - { - mSavedValues[control] = control->getValue(); - } - } - - // Push children onto the end of the work stack - for (child_list_t::const_iterator iter = curview->getChildList()->begin(); - iter != curview->getChildList()->end(); ++iter) - { - view_stack.push_back(*iter); - } - } + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list view_stack; + view_stack.push_back(this); + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLUICtrl* ctrl = dynamic_cast(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + mSavedValues[control] = control->getValue(); + } + } + + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } } void LLFloaterPreferenceProxy::onBtnOk() { - // commit any outstanding text entry - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - } - - // Save SOCKS proxy credentials securely if password auth is enabled - LLRadioGroup* socksAuth = getChild("socks5_auth_type"); - if (socksAuth->getSelectedValue().asString() == "UserPass") - { - LLSD socks_id = LLSD::emptyMap(); - socks_id["type"] = "SOCKS5"; - socks_id["username"] = getChild("socks5_username")->getValue().asString(); - - LLSD socks_authenticator = LLSD::emptyMap(); - socks_authenticator["type"] = "SOCKS5"; - socks_authenticator["creds"] = getChild("socks5_password")->getValue().asString(); - - // Using "SOCKS5" as the "grid" argument since the same proxy - // settings will be used for all grids and because there is no - // way to specify the type of credential. - LLPointer socks_cred = gSecAPIHandler->createCredential("SOCKS5", socks_id, socks_authenticator); - gSecAPIHandler->saveCredential(socks_cred, true); - } - else - { - // Clear SOCKS5 credentials since they are no longer needed. - LLPointer socks_cred = new LLCredential("SOCKS5"); - gSecAPIHandler->deleteCredential(socks_cred); - } - - closeFloater(false); + // commit any outstanding text entry + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + } + + // Save SOCKS proxy credentials securely if password auth is enabled + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if (socksAuth->getSelectedValue().asString() == "UserPass") + { + LLSD socks_id = LLSD::emptyMap(); + socks_id["type"] = "SOCKS5"; + socks_id["username"] = getChild("socks5_username")->getValue().asString(); + + LLSD socks_authenticator = LLSD::emptyMap(); + socks_authenticator["type"] = "SOCKS5"; + socks_authenticator["creds"] = getChild("socks5_password")->getValue().asString(); + + // Using "SOCKS5" as the "grid" argument since the same proxy + // settings will be used for all grids and because there is no + // way to specify the type of credential. + LLPointer socks_cred = gSecAPIHandler->createCredential("SOCKS5", socks_id, socks_authenticator); + gSecAPIHandler->saveCredential(socks_cred, true); + } + else + { + // Clear SOCKS5 credentials since they are no longer needed. + LLPointer socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + } + + closeFloater(false); } void LLFloaterPreferenceProxy::onBtnCancel() { - if (hasFocus()) - { - LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); - if (cur_focus && cur_focus->acceptsTextInput()) - { - cur_focus->onCommit(); - } - refresh(); - } + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus && cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + } + refresh(); + } - cancel(); + cancel(); } void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting) { - cancel(); + cancel(); } void LLFloaterPreferenceProxy::cancel() { - for (control_values_map_t::iterator iter = mSavedValues.begin(); - iter != mSavedValues.end(); ++iter) - { - LLControlVariable* control = iter->first; - LLSD ctrl_value = iter->second; - control->set(ctrl_value); - } - mSocksSettingsDirty = false; - closeFloater(); + for (control_values_map_t::iterator iter = mSavedValues.begin(); + iter != mSavedValues.end(); ++iter) + { + LLControlVariable* control = iter->first; + LLSD ctrl_value = iter->second; + control->set(ctrl_value); + } + mSocksSettingsDirty = false; + closeFloater(); } -void LLFloaterPreferenceProxy::onChangeSocksSettings() +void LLFloaterPreferenceProxy::onChangeSocksSettings() { - mSocksSettingsDirty = true; + mSocksSettingsDirty = true; - LLRadioGroup* socksAuth = getChild("socks5_auth_type"); - if (socksAuth->getSelectedValue().asString() == "None") - { - getChild("socks5_username")->setEnabled(false); - getChild("socks5_password")->setEnabled(false); - } - else - { - getChild("socks5_username")->setEnabled(true); - getChild("socks5_password")->setEnabled(true); - } + LLRadioGroup* socksAuth = getChild("socks5_auth_type"); + if (socksAuth->getSelectedValue().asString() == "None") + { + getChild("socks5_username")->setEnabled(false); + getChild("socks5_password")->setEnabled(false); + } + else + { + getChild("socks5_username")->setEnabled(true); + getChild("socks5_password")->setEnabled(true); + } - // Check for invalid states for the other HTTP proxy radio - LLRadioGroup* otherHttpProxy = getChild("other_http_proxy_type"); - if ((otherHttpProxy->getSelectedValue().asString() == "Socks" && - getChild("socks_proxy_enabled")->get() == FALSE )||( - otherHttpProxy->getSelectedValue().asString() == "Web" && - getChild("web_proxy_enabled")->get() == FALSE ) ) - { - otherHttpProxy->selectFirstItem(); - } + // Check for invalid states for the other HTTP proxy radio + LLRadioGroup* otherHttpProxy = getChild("other_http_proxy_type"); + if ((otherHttpProxy->getSelectedValue().asString() == "Socks" && + getChild("socks_proxy_enabled")->get() == FALSE )||( + otherHttpProxy->getSelectedValue().asString() == "Web" && + getChild("web_proxy_enabled")->get() == FALSE ) ) + { + otherHttpProxy->selectFirstItem(); + } } void LLFloaterPreference::onUpdateFilterTerm(bool force) { - LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() ); - LLWStringUtil::toLower( seachValue ); + LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() ); + LLWStringUtil::toLower( seachValue ); - if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force)) - return; + if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force)) + return; if (mSearchDataDirty) { @@ -3282,17 +3282,17 @@ void LLFloaterPreference::onUpdateFilterTerm(bool force) collectSearchableItems(); } - mSearchData->mLastFilter = seachValue; + mSearchData->mLastFilter = seachValue; - if( !mSearchData->mRootTab ) - return; + if( !mSearchData->mRootTab ) + return; - mSearchData->mRootTab->hightlightAndHide( seachValue ); + mSearchData->mRootTab->hightlightAndHide( seachValue ); filterIgnorableNotifications(); - LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); - if( pRoot ) - pRoot->selectFirstTab(); + LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); + if( pRoot ) + pRoot->selectFirstTab(); } void LLFloaterPreference::filterIgnorableNotifications() @@ -3308,91 +3308,91 @@ void LLFloaterPreference::filterIgnorableNotifications() void collectChildren( LLView const *aView, ll::prefs::PanelDataPtr aParentPanel, ll::prefs::TabContainerDataPtr aParentTabContainer ) { - if( !aView ) - return; - - llassert_always( aParentPanel || aParentTabContainer ); - - LLView::child_list_const_iter_t itr = aView->beginChild(); - LLView::child_list_const_iter_t itrEnd = aView->endChild(); - - while( itr != itrEnd ) - { - LLView *pView = *itr; - ll::prefs::PanelDataPtr pCurPanelData = aParentPanel; - ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer; - if( !pView ) - continue; - LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView ); - LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView ); - ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView ); - - if( pTabContainer ) - { - pCurPanelData.reset(); - - pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); - pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer ); - pCurTabContainer->mLabel = pTabContainer->getLabel(); - pCurTabContainer->mPanel = 0; - - if( aParentPanel ) - aParentPanel->mChildPanel.push_back( pCurTabContainer ); - if( aParentTabContainer ) - aParentTabContainer->mChildPanel.push_back( pCurTabContainer ); - } - else if( pPanel ) - { - pCurTabContainer.reset(); - - pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData ); - pCurPanelData->mPanel = pPanel; - pCurPanelData->mLabel = pPanel->getLabel(); - - llassert_always( aParentPanel || aParentTabContainer ); - - if( aParentTabContainer ) - aParentTabContainer->mChildPanel.push_back( pCurPanelData ); - else if( aParentPanel ) - aParentPanel->mChildPanel.push_back( pCurPanelData ); - } - else if( pSCtrl && pSCtrl->getSearchText().size() ) - { - ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() ); - item->mView = pView; - item->mCtrl = pSCtrl; - - item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() ); - LLWStringUtil::toLower( item->mLabel ); - - llassert_always( aParentPanel || aParentTabContainer ); - - if( aParentPanel ) - aParentPanel->mChildren.push_back( item ); - if( aParentTabContainer ) - aParentTabContainer->mChildren.push_back( item ); - } - collectChildren( pView, pCurPanelData, pCurTabContainer ); - ++itr; - } + if( !aView ) + return; + + llassert_always( aParentPanel || aParentTabContainer ); + + LLView::child_list_const_iter_t itr = aView->beginChild(); + LLView::child_list_const_iter_t itrEnd = aView->endChild(); + + while( itr != itrEnd ) + { + LLView *pView = *itr; + ll::prefs::PanelDataPtr pCurPanelData = aParentPanel; + ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer; + if( !pView ) + continue; + LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView ); + LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView ); + ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView ); + + if( pTabContainer ) + { + pCurPanelData.reset(); + + pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); + pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer ); + pCurTabContainer->mLabel = pTabContainer->getLabel(); + pCurTabContainer->mPanel = 0; + + if( aParentPanel ) + aParentPanel->mChildPanel.push_back( pCurTabContainer ); + if( aParentTabContainer ) + aParentTabContainer->mChildPanel.push_back( pCurTabContainer ); + } + else if( pPanel ) + { + pCurTabContainer.reset(); + + pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData ); + pCurPanelData->mPanel = pPanel; + pCurPanelData->mLabel = pPanel->getLabel(); + + llassert_always( aParentPanel || aParentTabContainer ); + + if( aParentTabContainer ) + aParentTabContainer->mChildPanel.push_back( pCurPanelData ); + else if( aParentPanel ) + aParentPanel->mChildPanel.push_back( pCurPanelData ); + } + else if( pSCtrl && pSCtrl->getSearchText().size() ) + { + ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() ); + item->mView = pView; + item->mCtrl = pSCtrl; + + item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() ); + LLWStringUtil::toLower( item->mLabel ); + + llassert_always( aParentPanel || aParentTabContainer ); + + if( aParentPanel ) + aParentPanel->mChildren.push_back( item ); + if( aParentTabContainer ) + aParentTabContainer->mChildren.push_back( item ); + } + collectChildren( pView, pCurPanelData, pCurTabContainer ); + ++itr; + } } void LLFloaterPreference::collectSearchableItems() { - mSearchData.reset( nullptr ); - LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); - if( mFilterEdit && pRoot ) - { - mSearchData.reset(new ll::prefs::SearchData() ); + mSearchData.reset( nullptr ); + LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); + if( mFilterEdit && pRoot ) + { + mSearchData.reset(new ll::prefs::SearchData() ); - ll::prefs::TabContainerDataPtr pRootTabcontainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); - pRootTabcontainer->mTabContainer = pRoot; - pRootTabcontainer->mLabel = pRoot->getLabel(); - mSearchData->mRootTab = pRootTabcontainer; + ll::prefs::TabContainerDataPtr pRootTabcontainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); + pRootTabcontainer->mTabContainer = pRoot; + pRootTabcontainer->mLabel = pRoot->getLabel(); + mSearchData->mRootTab = pRootTabcontainer; - collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); - } - mSearchDataDirty = false; + collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); + } + mSearchDataDirty = false; } void LLFloaterPreference::saveIgnoredNotifications() diff --git a/indra/newview/llfloaterregionrestarting.cpp b/indra/newview/llfloaterregionrestarting.cpp index 6817cce5f6..d37a2912a0 100644 --- a/indra/newview/llfloaterregionrestarting.cpp +++ b/indra/newview/llfloaterregionrestarting.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterregionrestarting.cpp * @brief Shows countdown timer during region restart * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,139 +38,139 @@ static S32 sSeconds; static U32 sShakeState; LLFloaterRegionRestarting::LLFloaterRegionRestarting(const LLSD& key) : - LLFloater(key), - LLEventTimer(1) + LLFloater(key), + LLEventTimer(1) { - mName = (std::string)key["NAME"]; - sSeconds = (LLSD::Integer)key["SECONDS"]; + mName = (std::string)key["NAME"]; + sSeconds = (LLSD::Integer)key["SECONDS"]; } LLFloaterRegionRestarting::~LLFloaterRegionRestarting() { - mRegionChangedConnection.disconnect(); + mRegionChangedConnection.disconnect(); } BOOL LLFloaterRegionRestarting::postBuild() { - mRegionChangedConnection = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionRestarting::regionChange, this)); + mRegionChangedConnection = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionRestarting::regionChange, this)); - LLStringUtil::format_map_t args; - std::string text; + LLStringUtil::format_map_t args; + std::string text; - args["[NAME]"] = mName; - text = getString("RegionName", args); - LLTextBox* textbox = getChild("region_name"); - textbox->setValue(text); + args["[NAME]"] = mName; + text = getString("RegionName", args); + LLTextBox* textbox = getChild("region_name"); + textbox->setValue(text); - sShakeState = SHAKE_START; + sShakeState = SHAKE_START; - refresh(); + refresh(); - return TRUE; + return TRUE; } void LLFloaterRegionRestarting::regionChange() { - close(); + close(); } bool LLFloaterRegionRestarting::tick() { - refresh(); + refresh(); - return false; + return false; } void LLFloaterRegionRestarting::refresh() { - LLStringUtil::format_map_t args; - std::string text; + LLStringUtil::format_map_t args; + std::string text; - args["[SECONDS]"] = llformat("%d", sSeconds); - getChild("restart_seconds")->setValue(getString("RestartSeconds", args)); + args["[SECONDS]"] = llformat("%d", sSeconds); + getChild("restart_seconds")->setValue(getString("RestartSeconds", args)); - sSeconds = sSeconds - 1; - if(sSeconds < 0.0) - { - sSeconds = 0; - } + sSeconds = sSeconds - 1; + if(sSeconds < 0.0) + { + sSeconds = 0; + } } void LLFloaterRegionRestarting::draw() { - LLFloater::draw(); - - const F32 SHAKE_INTERVAL = 0.025; - const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this - const F32 SHAKE_INITIAL_MAGNITUDE = 1.5; - const F32 SHAKE_HORIZONTAL_BIAS = 0.25; - F32 time_shaking; - - if(SHAKE_START == sShakeState) - { - mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); - sShakeState = SHAKE_LEFT; - mShakeIterations = 0; - mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE; - } - - if(SHAKE_DONE != sShakeState && mShakeTimer.hasExpired()) - { - gAgentCamera.unlockView(); - - switch(sShakeState) - { - case SHAKE_LEFT: - gAgentCamera.setPanLeftKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); - sShakeState = SHAKE_UP; - break; - - case SHAKE_UP: - gAgentCamera.setPanUpKey(mShakeMagnitude); - sShakeState = SHAKE_RIGHT; - break; - - case SHAKE_RIGHT: - gAgentCamera.setPanRightKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); - sShakeState = SHAKE_DOWN; - break; - - case SHAKE_DOWN: - gAgentCamera.setPanDownKey(mShakeMagnitude); - mShakeIterations++; - time_shaking = SHAKE_INTERVAL * (mShakeIterations * 4 /* left, up, right, down */); - if(SHAKE_TOTAL_DURATION <= time_shaking) - { - sShakeState = SHAKE_DONE; - mShakeMagnitude = 0.0; - } - else - { - sShakeState = SHAKE_LEFT; - F32 percent_done_shaking = (SHAKE_TOTAL_DURATION - time_shaking) / SHAKE_TOTAL_DURATION; - mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE * (percent_done_shaking * percent_done_shaking); // exponential decay - } - break; - - default: - break; - } - mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); - } + LLFloater::draw(); + + const F32 SHAKE_INTERVAL = 0.025; + const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this + const F32 SHAKE_INITIAL_MAGNITUDE = 1.5; + const F32 SHAKE_HORIZONTAL_BIAS = 0.25; + F32 time_shaking; + + if(SHAKE_START == sShakeState) + { + mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); + sShakeState = SHAKE_LEFT; + mShakeIterations = 0; + mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE; + } + + if(SHAKE_DONE != sShakeState && mShakeTimer.hasExpired()) + { + gAgentCamera.unlockView(); + + switch(sShakeState) + { + case SHAKE_LEFT: + gAgentCamera.setPanLeftKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); + sShakeState = SHAKE_UP; + break; + + case SHAKE_UP: + gAgentCamera.setPanUpKey(mShakeMagnitude); + sShakeState = SHAKE_RIGHT; + break; + + case SHAKE_RIGHT: + gAgentCamera.setPanRightKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); + sShakeState = SHAKE_DOWN; + break; + + case SHAKE_DOWN: + gAgentCamera.setPanDownKey(mShakeMagnitude); + mShakeIterations++; + time_shaking = SHAKE_INTERVAL * (mShakeIterations * 4 /* left, up, right, down */); + if(SHAKE_TOTAL_DURATION <= time_shaking) + { + sShakeState = SHAKE_DONE; + mShakeMagnitude = 0.0; + } + else + { + sShakeState = SHAKE_LEFT; + F32 percent_done_shaking = (SHAKE_TOTAL_DURATION - time_shaking) / SHAKE_TOTAL_DURATION; + mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE * (percent_done_shaking * percent_done_shaking); // exponential decay + } + break; + + default: + break; + } + mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); + } } void LLFloaterRegionRestarting::close() { - LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance("region_restarting"); + LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance("region_restarting"); - if (floaterp) - { - floaterp->closeFloater(); - } + if (floaterp) + { + floaterp->closeFloater(); + } } void LLFloaterRegionRestarting::updateTime(S32 time) { - sSeconds = time; - sShakeState = SHAKE_START; + sSeconds = time; + sShakeState = SHAKE_START; } diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h index 6d3639c40c..52f067fa94 100644 --- a/indra/newview/llfloaterregionrestarting.h +++ b/indra/newview/llfloaterregionrestarting.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterregionrestarting.h * @brief Shows countdown timer during region restart * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,37 +33,37 @@ class LLFloaterRegionRestarting : public LLFloater, public LLEventTimer { - friend class LLFloaterReg; + friend class LLFloaterReg; public: - static void close(); - static void updateTime(S32 time); + static void close(); + static void updateTime(S32 time); private: - LLFloaterRegionRestarting(const LLSD& key); - virtual ~LLFloaterRegionRestarting(); - BOOL postBuild() override; - bool tick() override; - void refresh() override; - void draw() override; - virtual void regionChange(); + LLFloaterRegionRestarting(const LLSD& key); + virtual ~LLFloaterRegionRestarting(); + BOOL postBuild() override; + bool tick() override; + void refresh() override; + void draw() override; + virtual void regionChange(); - std::string mName; - U32 mShakeIterations; - F32 mShakeMagnitude; - LLTimer mShakeTimer; + std::string mName; + U32 mShakeIterations; + F32 mShakeMagnitude; + LLTimer mShakeTimer; - boost::signals2::connection mRegionChangedConnection; + boost::signals2::connection mRegionChangedConnection; - enum - { - SHAKE_START, - SHAKE_LEFT, - SHAKE_UP, - SHAKE_RIGHT, - SHAKE_DOWN, - SHAKE_DONE - }; + enum + { + SHAKE_START, + SHAKE_LEFT, + SHAKE_UP, + SHAKE_RIGHT, + SHAKE_DOWN, + SHAKE_DONE + }; }; #endif // LL_LLFLOATERREGIONRESTARTING_H diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index e1df6a4b1f..751990b3b6 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloatersettingsdebug.cpp * @brief floater for debugging internal viewer settings * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, 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$ */ @@ -37,12 +37,12 @@ #include "llclipboard.h" -LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) +LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) : LLFloater(key), mSettingList(NULL) { - mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); - mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); + mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); + mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); } LLFloaterSettingsDebug::~LLFloaterSettingsDebug() @@ -68,7 +68,7 @@ BOOL LLFloaterSettingsDebug::postBuild() gSavedSettings.getControl("DebugSettingsHideDefault")->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateList, this, false)); - return TRUE; + return TRUE; } void LLFloaterSettingsDebug::draw() @@ -80,7 +80,7 @@ void LLFloaterSettingsDebug::draw() updateControl(controlp); } - LLFloater::draw(); + LLFloater::draw(); } void LLFloaterSettingsDebug::onCommitSettings() @@ -92,78 +92,78 @@ void LLFloaterSettingsDebug::onCommitSettings() } LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata(); - if (!controlp) - { - return; - } - - LLVector3 vector; - LLVector3d vectord; - LLQuaternion quat; - LLRect rect; - LLColor4 col4; - LLColor3 col3; - LLColor4U col4U; - LLColor4 color_with_alpha; - - switch(controlp->type()) - { - case TYPE_U32: - controlp->set(getChild("val_spinner_1")->getValue()); - break; - case TYPE_S32: - controlp->set(getChild("val_spinner_1")->getValue()); - break; - case TYPE_F32: - controlp->set(LLSD(getChild("val_spinner_1")->getValue().asReal())); - break; - case TYPE_BOOLEAN: - controlp->set(getChild("boolean_combo")->getValue()); - break; - case TYPE_STRING: - controlp->set(LLSD(getChild("val_text")->getValue().asString())); - break; - case TYPE_VEC3: - vector.mV[VX] = (F32)getChild("val_spinner_1")->getValue().asReal(); - vector.mV[VY] = (F32)getChild("val_spinner_2")->getValue().asReal(); - vector.mV[VZ] = (F32)getChild("val_spinner_3")->getValue().asReal(); - controlp->set(vector.getValue()); - break; - case TYPE_VEC3D: - vectord.mdV[VX] = getChild("val_spinner_1")->getValue().asReal(); - vectord.mdV[VY] = getChild("val_spinner_2")->getValue().asReal(); - vectord.mdV[VZ] = getChild("val_spinner_3")->getValue().asReal(); - controlp->set(vectord.getValue()); - break; - case TYPE_QUAT: - quat.mQ[VX] = getChild("val_spinner_1")->getValue().asReal(); - quat.mQ[VY] = getChild("val_spinner_2")->getValue().asReal(); - quat.mQ[VZ] = getChild("val_spinner_3")->getValue().asReal(); - quat.mQ[VS] = getChild("val_spinner_4")->getValue().asReal();; - controlp->set(quat.getValue()); - break; - case TYPE_RECT: - rect.mLeft = getChild("val_spinner_1")->getValue().asInteger(); - rect.mRight = getChild("val_spinner_2")->getValue().asInteger(); - rect.mBottom = getChild("val_spinner_3")->getValue().asInteger(); - rect.mTop = getChild("val_spinner_4")->getValue().asInteger(); - controlp->set(rect.getValue()); - break; - case TYPE_COL4: - col3.setValue(getChild("val_color_swatch")->getValue()); - col4 = LLColor4(col3, (F32)getChild("val_spinner_4")->getValue().asReal()); - controlp->set(col4.getValue()); - break; - case TYPE_COL3: - controlp->set(getChild("val_color_swatch")->getValue()); - //col3.mV[VRED] = (F32)floaterp->getChild("val_spinner_1")->getValue().asC(); - //col3.mV[VGREEN] = (F32)floaterp->getChild("val_spinner_2")->getValue().asReal(); - //col3.mV[VBLUE] = (F32)floaterp->getChild("val_spinner_3")->getValue().asReal(); - //controlp->set(col3.getValue()); - break; - default: - break; - } + if (!controlp) + { + return; + } + + LLVector3 vector; + LLVector3d vectord; + LLQuaternion quat; + LLRect rect; + LLColor4 col4; + LLColor3 col3; + LLColor4U col4U; + LLColor4 color_with_alpha; + + switch(controlp->type()) + { + case TYPE_U32: + controlp->set(getChild("val_spinner_1")->getValue()); + break; + case TYPE_S32: + controlp->set(getChild("val_spinner_1")->getValue()); + break; + case TYPE_F32: + controlp->set(LLSD(getChild("val_spinner_1")->getValue().asReal())); + break; + case TYPE_BOOLEAN: + controlp->set(getChild("boolean_combo")->getValue()); + break; + case TYPE_STRING: + controlp->set(LLSD(getChild("val_text")->getValue().asString())); + break; + case TYPE_VEC3: + vector.mV[VX] = (F32)getChild("val_spinner_1")->getValue().asReal(); + vector.mV[VY] = (F32)getChild("val_spinner_2")->getValue().asReal(); + vector.mV[VZ] = (F32)getChild("val_spinner_3")->getValue().asReal(); + controlp->set(vector.getValue()); + break; + case TYPE_VEC3D: + vectord.mdV[VX] = getChild("val_spinner_1")->getValue().asReal(); + vectord.mdV[VY] = getChild("val_spinner_2")->getValue().asReal(); + vectord.mdV[VZ] = getChild("val_spinner_3")->getValue().asReal(); + controlp->set(vectord.getValue()); + break; + case TYPE_QUAT: + quat.mQ[VX] = getChild("val_spinner_1")->getValue().asReal(); + quat.mQ[VY] = getChild("val_spinner_2")->getValue().asReal(); + quat.mQ[VZ] = getChild("val_spinner_3")->getValue().asReal(); + quat.mQ[VS] = getChild("val_spinner_4")->getValue().asReal();; + controlp->set(quat.getValue()); + break; + case TYPE_RECT: + rect.mLeft = getChild("val_spinner_1")->getValue().asInteger(); + rect.mRight = getChild("val_spinner_2")->getValue().asInteger(); + rect.mBottom = getChild("val_spinner_3")->getValue().asInteger(); + rect.mTop = getChild("val_spinner_4")->getValue().asInteger(); + controlp->set(rect.getValue()); + break; + case TYPE_COL4: + col3.setValue(getChild("val_color_swatch")->getValue()); + col4 = LLColor4(col3, (F32)getChild("val_spinner_4")->getValue().asReal()); + controlp->set(col4.getValue()); + break; + case TYPE_COL3: + controlp->set(getChild("val_color_swatch")->getValue()); + //col3.mV[VRED] = (F32)floaterp->getChild("val_spinner_1")->getValue().asC(); + //col3.mV[VGREEN] = (F32)floaterp->getChild("val_spinner_2")->getValue().asReal(); + //col3.mV[VBLUE] = (F32)floaterp->getChild("val_spinner_3")->getValue().asReal(); + //controlp->set(col3.getValue()); + break; + default: + break; + } updateDefaultColumn(controlp); } @@ -186,27 +186,27 @@ void LLFloaterSettingsDebug::onClickDefault() // we've switched controls, or doing per-frame update, so update spinners, etc. void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) { - LLSpinCtrl* spinner1 = getChild("val_spinner_1"); - LLSpinCtrl* spinner2 = getChild("val_spinner_2"); - LLSpinCtrl* spinner3 = getChild("val_spinner_3"); - LLSpinCtrl* spinner4 = getChild("val_spinner_4"); - LLColorSwatchCtrl* color_swatch = getChild("val_color_swatch"); - - if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) - { - LL_WARNS() << "Could not find all desired controls by name" - << LL_ENDL; - return; - } + LLSpinCtrl* spinner1 = getChild("val_spinner_1"); + LLSpinCtrl* spinner2 = getChild("val_spinner_2"); + LLSpinCtrl* spinner3 = getChild("val_spinner_3"); + LLSpinCtrl* spinner4 = getChild("val_spinner_4"); + LLColorSwatchCtrl* color_swatch = getChild("val_color_swatch"); + + if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) + { + LL_WARNS() << "Could not find all desired controls by name" + << LL_ENDL; + return; + } hideUIControls(); - if (controlp && !isSettingHidden(controlp)) - { - eControlType type = controlp->type(); + if (controlp && !isSettingHidden(controlp)) + { + eControlType type = controlp->type(); - //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame - getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); + //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame + getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); getChildView("default_btn")->setVisible(true); mSettingName->setVisible(true); mSettingName->setText(controlp->getName()); @@ -224,259 +224,259 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) mComment->setText(controlp->getComment()); } - spinner1->setMaxValue(F32_MAX); - spinner2->setMaxValue(F32_MAX); - spinner3->setMaxValue(F32_MAX); - spinner4->setMaxValue(F32_MAX); - spinner1->setMinValue(-F32_MAX); - spinner2->setMinValue(-F32_MAX); - spinner3->setMinValue(-F32_MAX); - spinner4->setMinValue(-F32_MAX); - if (!spinner1->hasFocus()) - { - spinner1->setIncrement(0.1f); - } - if (!spinner2->hasFocus()) - { - spinner2->setIncrement(0.1f); - } - if (!spinner3->hasFocus()) - { - spinner3->setIncrement(0.1f); - } - if (!spinner4->hasFocus()) - { - spinner4->setIncrement(0.1f); - } - - LLSD sd = controlp->get(); - switch(type) - { - case TYPE_U32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setValue(sd); - spinner1->setMinValue((F32)U32_MIN); - spinner1->setMaxValue((F32)U32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); - } - break; - case TYPE_S32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setValue(sd); - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); - } - break; - case TYPE_F32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(sd); - } - break; - case TYPE_BOOLEAN: - if (!getChild("boolean_combo")->hasFocus()) - { - if (sd.asBoolean()) - { - getChild("boolean_combo")->setValue(LLSD("true")); - } - else - { - getChild("boolean_combo")->setValue(LLSD("")); - } - } - break; - case TYPE_STRING: - getChildView("val_text")->setVisible( TRUE); - if (!getChild("val_text")->hasFocus()) - { - getChild("val_text")->setValue(sd); - } - break; - case TYPE_VEC3: - { - LLVector3 v; - v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); - } - break; - } - case TYPE_VEC3D: - { - LLVector3d v; - v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); - } - break; - } - case TYPE_QUAT: - { - LLQuaternion q; - q.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("S")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(4); - spinner1->setValue(q.mQ[VX]); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(4); - spinner2->setValue(q.mQ[VY]); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(4); - spinner3->setValue(q.mQ[VZ]); - } - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(4); - spinner4->setValue(q.mQ[VS]); - } - break; - } - case TYPE_RECT: - { - LLRect r; - r.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("Left")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Right")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Bottom")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Top")); - if (!spinner1->hasFocus()) - { - spinner1->setPrecision(0); - spinner1->setValue(r.mLeft); - } - if (!spinner2->hasFocus()) - { - spinner2->setPrecision(0); - spinner2->setValue(r.mRight); - } - if (!spinner3->hasFocus()) - { - spinner3->setPrecision(0); - spinner3->setValue(r.mBottom); - } - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(0); - spinner4->setValue(r.mTop); - } - - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - - spinner2->setMinValue((F32)S32_MIN); - spinner2->setMaxValue((F32)S32_MAX); - spinner2->setIncrement(1.f); - - spinner3->setMinValue((F32)S32_MIN); - spinner3->setMaxValue((F32)S32_MAX); - spinner3->setIncrement(1.f); - - spinner4->setMinValue((F32)S32_MIN); - spinner4->setMaxValue((F32)S32_MAX); - spinner4->setIncrement(1.f); - break; - } - case TYPE_COL4: - { - LLColor4 clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - // only set if changed so color picker doesn't update - if(clr != LLColor4(color_swatch->getValue())) - { - color_swatch->set(LLColor4(sd), TRUE, FALSE); - } - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Alpha")); - if (!spinner4->hasFocus()) - { - spinner4->setPrecision(3); - spinner4->setMinValue(0.0); - spinner4->setMaxValue(1.f); - spinner4->setValue(clr.mV[VALPHA]); - } - break; - } - case TYPE_COL3: - { - LLColor3 clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - color_swatch->setValue(sd); - break; - } - default: - mComment->setText(std::string("unknown")); - break; - } - } + spinner1->setMaxValue(F32_MAX); + spinner2->setMaxValue(F32_MAX); + spinner3->setMaxValue(F32_MAX); + spinner4->setMaxValue(F32_MAX); + spinner1->setMinValue(-F32_MAX); + spinner2->setMinValue(-F32_MAX); + spinner3->setMinValue(-F32_MAX); + spinner4->setMinValue(-F32_MAX); + if (!spinner1->hasFocus()) + { + spinner1->setIncrement(0.1f); + } + if (!spinner2->hasFocus()) + { + spinner2->setIncrement(0.1f); + } + if (!spinner3->hasFocus()) + { + spinner3->setIncrement(0.1f); + } + if (!spinner4->hasFocus()) + { + spinner4->setIncrement(0.1f); + } + + LLSD sd = controlp->get(); + switch(type) + { + case TYPE_U32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setValue(sd); + spinner1->setMinValue((F32)U32_MIN); + spinner1->setMaxValue((F32)U32_MAX); + spinner1->setIncrement(1.f); + spinner1->setPrecision(0); + } + break; + case TYPE_S32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setValue(sd); + spinner1->setMinValue((F32)S32_MIN); + spinner1->setMaxValue((F32)S32_MAX); + spinner1->setIncrement(1.f); + spinner1->setPrecision(0); + } + break; + case TYPE_F32: + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("value")); // Debug, don't translate + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(sd); + } + break; + case TYPE_BOOLEAN: + if (!getChild("boolean_combo")->hasFocus()) + { + if (sd.asBoolean()) + { + getChild("boolean_combo")->setValue(LLSD("true")); + } + else + { + getChild("boolean_combo")->setValue(LLSD("")); + } + } + break; + case TYPE_STRING: + getChildView("val_text")->setVisible( TRUE); + if (!getChild("val_text")->hasFocus()) + { + getChild("val_text")->setValue(sd); + } + break; + case TYPE_VEC3: + { + LLVector3 v; + v.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(v[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(3); + spinner2->setValue(v[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(3); + spinner3->setValue(v[VZ]); + } + break; + } + case TYPE_VEC3D: + { + LLVector3d v; + v.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(3); + spinner1->setValue(v[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(3); + spinner2->setValue(v[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(3); + spinner3->setValue(v[VZ]); + } + break; + } + case TYPE_QUAT: + { + LLQuaternion q; + q.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("X")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Y")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Z")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("S")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(4); + spinner1->setValue(q.mQ[VX]); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(4); + spinner2->setValue(q.mQ[VY]); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(4); + spinner3->setValue(q.mQ[VZ]); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(4); + spinner4->setValue(q.mQ[VS]); + } + break; + } + case TYPE_RECT: + { + LLRect r; + r.setValue(sd); + spinner1->setVisible(TRUE); + spinner1->setLabel(std::string("Left")); + spinner2->setVisible(TRUE); + spinner2->setLabel(std::string("Right")); + spinner3->setVisible(TRUE); + spinner3->setLabel(std::string("Bottom")); + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("Top")); + if (!spinner1->hasFocus()) + { + spinner1->setPrecision(0); + spinner1->setValue(r.mLeft); + } + if (!spinner2->hasFocus()) + { + spinner2->setPrecision(0); + spinner2->setValue(r.mRight); + } + if (!spinner3->hasFocus()) + { + spinner3->setPrecision(0); + spinner3->setValue(r.mBottom); + } + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(0); + spinner4->setValue(r.mTop); + } + + spinner1->setMinValue((F32)S32_MIN); + spinner1->setMaxValue((F32)S32_MAX); + spinner1->setIncrement(1.f); + + spinner2->setMinValue((F32)S32_MIN); + spinner2->setMaxValue((F32)S32_MAX); + spinner2->setIncrement(1.f); + + spinner3->setMinValue((F32)S32_MIN); + spinner3->setMaxValue((F32)S32_MAX); + spinner3->setIncrement(1.f); + + spinner4->setMinValue((F32)S32_MIN); + spinner4->setMaxValue((F32)S32_MAX); + spinner4->setIncrement(1.f); + break; + } + case TYPE_COL4: + { + LLColor4 clr; + clr.setValue(sd); + color_swatch->setVisible(TRUE); + // only set if changed so color picker doesn't update + if(clr != LLColor4(color_swatch->getValue())) + { + color_swatch->set(LLColor4(sd), TRUE, FALSE); + } + spinner4->setVisible(TRUE); + spinner4->setLabel(std::string("Alpha")); + if (!spinner4->hasFocus()) + { + spinner4->setPrecision(3); + spinner4->setMinValue(0.0); + spinner4->setMaxValue(1.f); + spinner4->setValue(clr.mV[VALPHA]); + } + break; + } + case TYPE_COL3: + { + LLColor3 clr; + clr.setValue(sd); + color_swatch->setVisible(TRUE); + color_swatch->setValue(sd); + break; + } + default: + mComment->setText(std::string("unknown")); + break; + } + } } @@ -500,7 +500,7 @@ void LLFloaterSettingsDebug::updateList(bool skip_selection) LLFloaterSettingsDebug* floater; std::string selected_setting; bool skip_selection; - f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection) + f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection) : setting_list(list), floater(floater), selected_setting(setting), skip_selection(skip_selection) {} virtual void apply(const std::string& name, LLControlVariable* control) { diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index 6ff3e344b4..e52d5ac863 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloatersettingsdebug.h * @brief floater for debugging internal viewer settings * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, 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$ */ @@ -33,30 +33,30 @@ class LLScrollListCtrl; class LLTextBox; -class LLFloaterSettingsDebug -: public LLFloater +class LLFloaterSettingsDebug +: public LLFloater { - friend class LLFloaterReg; + friend class LLFloaterReg; public: - virtual BOOL postBuild(); - virtual void draw(); + virtual BOOL postBuild(); + virtual void draw(); - void updateControl(LLControlVariable* control); + void updateControl(LLControlVariable* control); - void onCommitSettings(); - void onClickDefault(); + void onCommitSettings(); + void onClickDefault(); void onClickCopy(); bool matchesSearchFilter(std::string setting_name); bool isSettingHidden(LLControlVariable* control); private: - // key - selects which settings to show, one of: - // "all", "base", "account", "skin" - LLFloaterSettingsDebug(const LLSD& key); - virtual ~LLFloaterSettingsDebug(); + // key - selects which settings to show, one of: + // "all", "base", "account", "skin" + LLFloaterSettingsDebug(const LLSD& key); + virtual ~LLFloaterSettingsDebug(); void updateList(bool skip_selection = false); void onSettingSelect(); @@ -66,9 +66,9 @@ private: void hideUIControls(); LLScrollListCtrl* mSettingList; - + protected: - class LLTextEditor* mComment; + class LLTextEditor* mComment; LLTextBox* mSettingName; LLButton* mCopyBtn; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 74b6218b46..4e35290a3b 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2008&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$ */ @@ -30,9 +30,9 @@ // *TODO: Translate error messgaes using notifications/alerts.xml -#include "llviewerprecompiledheaders.h" // Precompiled headers +#include "llviewerprecompiledheaders.h" // Precompiled headers -#include "llfloateruipreview.h" // Own header +#include "llfloateruipreview.h" // Own header // Internal utility #include "lldiriterator.h" @@ -56,10 +56,10 @@ #include "lltooltip.h" #include "llviewermenu.h" #include "llrngwriter.h" -#include "llfloater.h" // superclass +#include "llfloater.h" // superclass #include "llfloaterreg.h" -#include "llscrollcontainer.h" // scroll container for overlapping elements -#include "lllivefile.h" // live file poll/stat/reload +#include "llscrollcontainer.h" // scroll container for overlapping elements +#include "lllivefile.h" // live file poll/stat/reload #include "llviewermenufile.h" // LLFilePickerReplyThread // Boost (for linux/unix command-line execv) @@ -84,8 +84,8 @@ static LLDefaultChildRegistry::Register register_overlap_panel(" static std::string get_xui_dir() { - std::string delim = gDirUtilp->getDirDelimiter(); - return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim; + std::string delim = gDirUtilp->getDirDelimiter(); + return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim; } // Forward declarations to avoid header dependencies @@ -107,115 +107,115 @@ class LLPreviewedFloater; class LLOverlapPanel : public LLPanel { public: - struct Params : public LLInitParam::Block - { - Params() {} - }; - LLOverlapPanel(Params p = Params()) : LLPanel(p), - mSpacing(10), - // mClickedElement(NULL), - mLastClickedElement(NULL) - { - mOriginalWidth = getRect().getWidth(); - mOriginalHeight = getRect().getHeight(); - } - virtual void draw(); - - typedef std::map > OverlapMap; - OverlapMap mOverlapMap; // map, of XUI element to a list of XUI elements it overlaps - - // LLView *mClickedElement; - LLView *mLastClickedElement; - int mOriginalWidth, mOriginalHeight, mSpacing; + struct Params : public LLInitParam::Block + { + Params() {} + }; + LLOverlapPanel(Params p = Params()) : LLPanel(p), + mSpacing(10), + // mClickedElement(NULL), + mLastClickedElement(NULL) + { + mOriginalWidth = getRect().getWidth(); + mOriginalHeight = getRect().getHeight(); + } + virtual void draw(); + + typedef std::map > OverlapMap; + OverlapMap mOverlapMap; // map, of XUI element to a list of XUI elements it overlaps + + // LLView *mClickedElement; + LLView *mLastClickedElement; + int mOriginalWidth, mOriginalHeight, mSpacing; }; class LLFloaterUIPreview : public LLFloater { public: - // Setup - LLFloaterUIPreview(const LLSD& key); - virtual ~LLFloaterUIPreview(); - - std::string getLocStr(S32 ID); // fetches the localization string based on what is selected in the drop-down menu - void displayFloater(BOOL click, S32 ID); // needs to be public so live file can call it when it finds an update - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onClose(bool app_quitting); - - void refreshList(); // refresh list (empty it out and fill it up from scratch) - void addFloaterEntry(const std::string& path); // add a single file's entry to the list of floaters - - static BOOL containerType(LLView* viewp); // check if the element is a container type and tree traverses need to look at its children - -public: - LLPreviewedFloater* mDisplayedFloater; // the floater which is currently being displayed - LLPreviewedFloater* mDisplayedFloater_2; // the floater which is currently being displayed - LLGUIPreviewLiveFile* mLiveFile; // live file for checking for updates to the currently-displayed XML file - LLOverlapPanel* mOverlapPanel; // custom overlapping elements panel - // BOOL mHighlightingDiffs; // bool for whether localization diffs are being highlighted or not - BOOL mHighlightingOverlaps; // bool for whether overlapping elements are being highlighted - - // typedef std::map,std::list > > DiffMap; // this version copies the lists etc., and thus is bad memory-wise - typedef std::list StringList; - typedef std::shared_ptr StringListPtr; - typedef std::map > DiffMap; - DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors + // Setup + LLFloaterUIPreview(const LLSD& key); + virtual ~LLFloaterUIPreview(); + + std::string getLocStr(S32 ID); // fetches the localization string based on what is selected in the drop-down menu + void displayFloater(BOOL click, S32 ID); // needs to be public so live file can call it when it finds an update + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + + void refreshList(); // refresh list (empty it out and fill it up from scratch) + void addFloaterEntry(const std::string& path); // add a single file's entry to the list of floaters + + static BOOL containerType(LLView* viewp); // check if the element is a container type and tree traverses need to look at its children + +public: + LLPreviewedFloater* mDisplayedFloater; // the floater which is currently being displayed + LLPreviewedFloater* mDisplayedFloater_2; // the floater which is currently being displayed + LLGUIPreviewLiveFile* mLiveFile; // live file for checking for updates to the currently-displayed XML file + LLOverlapPanel* mOverlapPanel; // custom overlapping elements panel + // BOOL mHighlightingDiffs; // bool for whether localization diffs are being highlighted or not + BOOL mHighlightingOverlaps; // bool for whether overlapping elements are being highlighted + + // typedef std::map,std::list > > DiffMap; // this version copies the lists etc., and thus is bad memory-wise + typedef std::list StringList; + typedef std::shared_ptr StringListPtr; + typedef std::map > DiffMap; + DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors private: - LLExternalEditor mExternalEditor; - - // XUI elements for this floater - LLScrollListCtrl* mFileList; // scroll list control for file list - LLLineEditor* mEditorPathTextBox; // text field for path to editor executable - LLLineEditor* mEditorArgsTextBox; // text field for arguments to editor executable - LLLineEditor* mDiffPathTextBox; // text field for path to diff file - LLButton* mDisplayFloaterBtn; // button to display primary floater - LLButton* mDisplayFloaterBtn_2; // button to display secondary floater - LLButton* mEditFloaterBtn; // button to edit floater - LLButton* mExecutableBrowseButton; // button to browse for executable - LLButton* mCloseOtherButton; // button to close primary displayed floater - LLButton* mCloseOtherButton_2; // button to close secondary displayed floater - LLButton* mDiffBrowseButton; // button to browse for diff file - LLButton* mToggleHighlightButton; // button to toggle highlight of files/elements with diffs - LLButton* mToggleOverlapButton; // button to togle overlap panel/highlighting - LLComboBox* mLanguageSelection; // combo box for primary language selection - LLComboBox* mLanguageSelection_2; // combo box for secondary language selection - S32 mLastDisplayedX, mLastDisplayedY; // stored position of last floater so the new one opens up in the same place - std::string mDelim; // the OS-specific delimiter character (/ or \) (*TODO: this shouldn't be needed, right?) - - std::string mSavedEditorPath; // stored editor path so closing this floater doesn't reset it - std::string mSavedEditorArgs; // stored editor args so closing this floater doesn't reset it - std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it - - // Internal functionality - static void popupAndPrintWarning(const std::string& warning); // pop up a warning - std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization - void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file - void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater - void highlightChangedFiles(); // look up the list of changed files to highlight and highlight them in the scroll list - void findOverlapsInChildren(LLView* parent); // fill the map below with element overlap information - static BOOL overlapIgnorable(LLView* viewp); // check it the element can be ignored for overlap/localization purposes - - // check if two elements overlap using their rectangles - // used instead of llrect functions because by adding a few pixels of leeway I can cut down drastically on the number of overlaps - BOOL elementOverlap(LLView* view1, LLView* view2); - - // Button/drop-down action listeners (self explanatory) - void onClickDisplayFloater(S32 id); - void onClickSaveFloater(S32 id); - void onClickSaveAll(S32 id); - void onClickEditFloater(); - void onClickBrowseForEditor(); - void getExecutablePath(const std::vector& filenames); - void onClickBrowseForDiffs(); - void getDiffsFilePath(const std::vector& filenames); - void onClickToggleDiffHighlighting(); - void onClickToggleOverlapping(); - void onClickCloseDisplayedFloater(S32 id); - void onLanguageComboSelect(LLUICtrl* ctrl); - void onClickExportSchema(); - void onClickShowRectangles(const LLSD& data); + LLExternalEditor mExternalEditor; + + // XUI elements for this floater + LLScrollListCtrl* mFileList; // scroll list control for file list + LLLineEditor* mEditorPathTextBox; // text field for path to editor executable + LLLineEditor* mEditorArgsTextBox; // text field for arguments to editor executable + LLLineEditor* mDiffPathTextBox; // text field for path to diff file + LLButton* mDisplayFloaterBtn; // button to display primary floater + LLButton* mDisplayFloaterBtn_2; // button to display secondary floater + LLButton* mEditFloaterBtn; // button to edit floater + LLButton* mExecutableBrowseButton; // button to browse for executable + LLButton* mCloseOtherButton; // button to close primary displayed floater + LLButton* mCloseOtherButton_2; // button to close secondary displayed floater + LLButton* mDiffBrowseButton; // button to browse for diff file + LLButton* mToggleHighlightButton; // button to toggle highlight of files/elements with diffs + LLButton* mToggleOverlapButton; // button to togle overlap panel/highlighting + LLComboBox* mLanguageSelection; // combo box for primary language selection + LLComboBox* mLanguageSelection_2; // combo box for secondary language selection + S32 mLastDisplayedX, mLastDisplayedY; // stored position of last floater so the new one opens up in the same place + std::string mDelim; // the OS-specific delimiter character (/ or \) (*TODO: this shouldn't be needed, right?) + + std::string mSavedEditorPath; // stored editor path so closing this floater doesn't reset it + std::string mSavedEditorArgs; // stored editor args so closing this floater doesn't reset it + std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it + + // Internal functionality + static void popupAndPrintWarning(const std::string& warning); // pop up a warning + std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization + void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file + void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater + void highlightChangedFiles(); // look up the list of changed files to highlight and highlight them in the scroll list + void findOverlapsInChildren(LLView* parent); // fill the map below with element overlap information + static BOOL overlapIgnorable(LLView* viewp); // check it the element can be ignored for overlap/localization purposes + + // check if two elements overlap using their rectangles + // used instead of llrect functions because by adding a few pixels of leeway I can cut down drastically on the number of overlaps + BOOL elementOverlap(LLView* view1, LLView* view2); + + // Button/drop-down action listeners (self explanatory) + void onClickDisplayFloater(S32 id); + void onClickSaveFloater(S32 id); + void onClickSaveAll(S32 id); + void onClickEditFloater(); + void onClickBrowseForEditor(); + void getExecutablePath(const std::vector& filenames); + void onClickBrowseForDiffs(); + void getDiffsFilePath(const std::vector& filenames); + void onClickToggleDiffHighlighting(); + void onClickToggleOverlapping(); + void onClickCloseDisplayedFloater(S32 id); + void onLanguageComboSelect(LLUICtrl* ctrl); + void onClickExportSchema(); + void onClickShowRectangles(const LLSD& data); }; //---------------------------------------------------------------------------- @@ -226,11 +226,11 @@ private: class LLLocalizationResetForcer { public: - LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID); - virtual ~LLLocalizationResetForcer(); + LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID); + virtual ~LLLocalizationResetForcer(); private: - std::string mSavedLocalization; // the localization before we change it + std::string mSavedLocalization; // the localization before we change it }; // Implementation of live file @@ -239,26 +239,26 @@ private: class LLGUIPreviewLiveFile : public LLLiveFile { public: - LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent); - virtual ~LLGUIPreviewLiveFile(); - LLFloaterUIPreview* mParent; - LLFadeEventTimer* mFadeTimer; // timer for fade-to-yellow-and-back effect to warn that file has been reloaded - BOOL mFirstFade; // setting this avoids showing the fade reload warning on first load - std::string mFileName; + LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent); + virtual ~LLGUIPreviewLiveFile(); + LLFloaterUIPreview* mParent; + LLFadeEventTimer* mFadeTimer; // timer for fade-to-yellow-and-back effect to warn that file has been reloaded + BOOL mFirstFade; // setting this avoids showing the fade reload warning on first load + std::string mFileName; protected: - bool loadFile(); + bool loadFile(); }; // Implementation of graphical fade in/out (on timer) for when XUI files are updated class LLFadeEventTimer : public LLEventTimer { public: - LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); - bool tick() override; - LLGUIPreviewLiveFile* mParent; + LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); + bool tick() override; + LLGUIPreviewLiveFile* mParent; private: - BOOL mFadingOut; // fades in then out; this is toggled in between - LLColor4 mOriginalColor; // original color; color is reset to this after fade is coimplete + BOOL mFadingOut; // fades in then out; this is toggled in between + LLColor4 mOriginalColor; // original color; color is reset to this after fade is coimplete }; // Implementation of previewed floater @@ -266,21 +266,21 @@ private: class LLPreviewedFloater : public LLFloater { public: - LLPreviewedFloater(LLFloaterUIPreview* floater, const Params& params) - : LLFloater(LLSD(), params), - mFloaterUIPreview(floater) - { - } + LLPreviewedFloater(LLFloaterUIPreview* floater, const Params& params) + : LLFloater(LLSD(), params), + mFloaterUIPreview(floater) + { + } - virtual void draw(); - BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - BOOL handleToolTip(S32 x, S32 y, MASK mask); - BOOL selectElement(LLView* parent, int x, int y, int depth); // select element to display its overlappers + virtual void draw(); + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + BOOL handleToolTip(S32 x, S32 y, MASK mask); + BOOL selectElement(LLView* parent, int x, int y, int depth); // select element to display its overlappers - LLFloaterUIPreview* mFloaterUIPreview; + LLFloaterUIPreview* mFloaterUIPreview; - // draw widget outlines - static bool sShowRectangles; + // draw widget outlines + static bool sShowRectangles; }; bool LLPreviewedFloater::sShowRectangles = false; @@ -291,507 +291,507 @@ bool LLPreviewedFloater::sShowRectangles = false; // Changes are made here LLLocalizationResetForcer::LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID) { - mSavedLocalization = LLUI::getInstance()->mSettingGroups["config"]->getString("Language"); // save current localization setting - LLUI::getInstance()->mSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in - // forcibly reset XUI paths with this new language - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), floater->getLocStr(ID)); + mSavedLocalization = LLUI::getInstance()->mSettingGroups["config"]->getString("Language"); // save current localization setting + LLUI::getInstance()->mSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in + // forcibly reset XUI paths with this new language + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), floater->getLocStr(ID)); } // Actually reset in destructor // Changes are reversed here LLLocalizationResetForcer::~LLLocalizationResetForcer() { - LLUI::getInstance()->mSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it - // forcibly reset XUI paths with this new language - gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), mSavedLocalization); + LLUI::getInstance()->mSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it + // forcibly reset XUI paths with this new language + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), mSavedLocalization); } // Live file constructor // Needs full path for LLLiveFile but needs just file name for this code, hence the reduntant arguments; easier than separating later LLGUIPreviewLiveFile::LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent) : mFileName(name), - mParent(parent), - mFirstFade(TRUE), - mFadeTimer(NULL), - LLLiveFile(path, 1.0) + mParent(parent), + mFirstFade(TRUE), + mFadeTimer(NULL), + LLLiveFile(path, 1.0) {} LLGUIPreviewLiveFile::~LLGUIPreviewLiveFile() { - mParent->mLiveFile = NULL; - if(mFadeTimer) - { - mFadeTimer->mParent = NULL; - // deletes itself; see lltimer.cpp - } + mParent->mLiveFile = NULL; + if(mFadeTimer) + { + mFadeTimer->mParent = NULL; + // deletes itself; see lltimer.cpp + } } // Live file load bool LLGUIPreviewLiveFile::loadFile() { - mParent->displayFloater(FALSE,1); // redisplay the floater - if(mFirstFade) // only fade if it wasn't just clicked on; can't use "clicked" BOOL below because of an oddity with setting LLLiveFile initial state - { - mFirstFade = FALSE; - } - else - { - if(mFadeTimer) - { - mFadeTimer->mParent = NULL; - } - mFadeTimer = new LLFadeEventTimer(0.05f,this); - } - return true; + mParent->displayFloater(FALSE,1); // redisplay the floater + if(mFirstFade) // only fade if it wasn't just clicked on; can't use "clicked" BOOL below because of an oddity with setting LLLiveFile initial state + { + mFirstFade = FALSE; + } + else + { + if(mFadeTimer) + { + mFadeTimer->mParent = NULL; + } + mFadeTimer = new LLFadeEventTimer(0.05f,this); + } + return true; } // Initialize fade event timer LLFadeEventTimer::LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent) - : mParent(parent), - mFadingOut(TRUE), - LLEventTimer(refresh) + : mParent(parent), + mFadingOut(TRUE), + LLEventTimer(refresh) { - mOriginalColor = mParent->mParent->mDisplayedFloater->getBackgroundColor(); + mOriginalColor = mParent->mParent->mDisplayedFloater->getBackgroundColor(); } // Single tick of fade event timer: increment the color bool LLFadeEventTimer::tick() { - float diff = 0.04f; - if(TRUE == mFadingOut) // set fade for in/out color direction - { - diff = -diff; - } - - if(NULL == mParent) // no more need to tick, so suicide - { - return true; - } - - // Set up colors - LLColor4 bg_color = mParent->mParent->mDisplayedFloater->getBackgroundColor(); - LLSD colors = bg_color.getValue(); - LLSD colors_old = colors; - - // Tick colors - colors[0] = colors[0].asReal() - diff; if(colors[0].asReal() < mOriginalColor.getValue()[0].asReal()) { colors[0] = colors_old[0]; } - colors[1] = colors[1].asReal() - diff; if(colors[1].asReal() < mOriginalColor.getValue()[1].asReal()) { colors[1] = colors_old[1]; } - colors[2] = colors[2].asReal() + diff; if(colors[2].asReal() > mOriginalColor.getValue()[2].asReal()) { colors[2] = colors_old[2]; } - - // Clamp and set colors - bg_color.setValue(colors); - bg_color.clamp(); // make sure we didn't exceed [0,1] - mParent->mParent->mDisplayedFloater->setBackgroundColor(bg_color); - - if(bg_color[2] <= 0.0f) // end of fade out, start fading in - { - mFadingOut = FALSE; - } - - return false; + float diff = 0.04f; + if(TRUE == mFadingOut) // set fade for in/out color direction + { + diff = -diff; + } + + if(NULL == mParent) // no more need to tick, so suicide + { + return true; + } + + // Set up colors + LLColor4 bg_color = mParent->mParent->mDisplayedFloater->getBackgroundColor(); + LLSD colors = bg_color.getValue(); + LLSD colors_old = colors; + + // Tick colors + colors[0] = colors[0].asReal() - diff; if(colors[0].asReal() < mOriginalColor.getValue()[0].asReal()) { colors[0] = colors_old[0]; } + colors[1] = colors[1].asReal() - diff; if(colors[1].asReal() < mOriginalColor.getValue()[1].asReal()) { colors[1] = colors_old[1]; } + colors[2] = colors[2].asReal() + diff; if(colors[2].asReal() > mOriginalColor.getValue()[2].asReal()) { colors[2] = colors_old[2]; } + + // Clamp and set colors + bg_color.setValue(colors); + bg_color.clamp(); // make sure we didn't exceed [0,1] + mParent->mParent->mDisplayedFloater->setBackgroundColor(bg_color); + + if(bg_color[2] <= 0.0f) // end of fade out, start fading in + { + mFadingOut = FALSE; + } + + return false; } // Constructor LLFloaterUIPreview::LLFloaterUIPreview(const LLSD& key) : LLFloater(key), - mDisplayedFloater(NULL), - mDisplayedFloater_2(NULL), - mLiveFile(NULL), - // sHighlightingDiffs(FALSE), - mHighlightingOverlaps(FALSE), - mLastDisplayedX(0), - mLastDisplayedY(0) + mDisplayedFloater(NULL), + mDisplayedFloater_2(NULL), + mLiveFile(NULL), + // sHighlightingDiffs(FALSE), + mHighlightingOverlaps(FALSE), + mLastDisplayedX(0), + mLastDisplayedY(0) { } // Destructor LLFloaterUIPreview::~LLFloaterUIPreview() { - // spawned floaters are deleted automatically, so we don't need to delete them here - - // save contents of textfields so it can be restored later if the floater is created again this session - mSavedEditorPath = mEditorPathTextBox->getText(); - mSavedEditorArgs = mEditorArgsTextBox->getText(); - mSavedDiffPath = mDiffPathTextBox->getText(); - - // delete live file if it exists - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } + // spawned floaters are deleted automatically, so we don't need to delete them here + + // save contents of textfields so it can be restored later if the floater is created again this session + mSavedEditorPath = mEditorPathTextBox->getText(); + mSavedEditorArgs = mEditorArgsTextBox->getText(); + mSavedDiffPath = mDiffPathTextBox->getText(); + + // delete live file if it exists + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } } // Perform post-build setup (defined in superclass) BOOL LLFloaterUIPreview::postBuild() { - LLPanel* main_panel_tmp = getChild("main_panel"); // get a pointer to the main panel in order to... - mFileList = main_panel_tmp->getChild("name_list"); // save pointer to file list - // Double-click opens the floater, for convenience - mFileList->setDoubleClickCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); - - setDefaultBtn("display_floater"); - // get pointers to buttons and link to callbacks - mLanguageSelection = main_panel_tmp->getChild("language_select_combo"); - mLanguageSelection->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); - mLanguageSelection_2 = main_panel_tmp->getChild("language_select_combo_2"); - mLanguageSelection_2->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); - LLPanel* editor_panel_tmp = main_panel_tmp->getChild("editor_panel"); - mDisplayFloaterBtn = main_panel_tmp->getChild("display_floater"); - mDisplayFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); - mDisplayFloaterBtn_2 = main_panel_tmp->getChild("display_floater_2"); - mDisplayFloaterBtn_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, SECONDARY_FLOATER)); - mToggleOverlapButton = main_panel_tmp->getChild("toggle_overlap_panel"); - mToggleOverlapButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleOverlapping, this)); - mCloseOtherButton = main_panel_tmp->getChild("close_displayed_floater"); - mCloseOtherButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, PRIMARY_FLOATER)); - mCloseOtherButton_2 = main_panel_tmp->getChild("close_displayed_floater_2"); - mCloseOtherButton_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, SECONDARY_FLOATER)); - mEditFloaterBtn = main_panel_tmp->getChild("edit_floater"); - mEditFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickEditFloater, this)); - mExecutableBrowseButton = editor_panel_tmp->getChild("browse_for_executable"); - LLPanel* vlt_panel_tmp = main_panel_tmp->getChild("vlt_panel"); - mExecutableBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForEditor, this)); - mDiffBrowseButton = vlt_panel_tmp->getChild("browse_for_vlt_diffs"); - mDiffBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForDiffs, this)); - mToggleHighlightButton = vlt_panel_tmp->getChild("toggle_vlt_diff_highlight"); - mToggleHighlightButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleDiffHighlighting, this)); - main_panel_tmp->getChild("save_floater")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveFloater, this, PRIMARY_FLOATER)); - main_panel_tmp->getChild("save_all_floaters")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveAll, this, PRIMARY_FLOATER)); - - getChild("export_schema")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickExportSchema, this)); - getChild("show_rectangles")->setCommitCallback( - boost::bind(&LLFloaterUIPreview::onClickShowRectangles, this, _2)); - - // get pointers to text fields - mEditorPathTextBox = editor_panel_tmp->getChild("executable_path_field"); - mEditorArgsTextBox = editor_panel_tmp->getChild("executable_args_field"); - mDiffPathTextBox = vlt_panel_tmp->getChild("vlt_diff_path_field"); - - // *HACK: restored saved editor path and args to textfields - mEditorPathTextBox->setText(mSavedEditorPath); - mEditorArgsTextBox->setText(mSavedEditorArgs); - mDiffPathTextBox->setText(mSavedDiffPath); - - // Set up overlap panel - mOverlapPanel = getChild("overlap_panel"); - - getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); - - mDelim = gDirUtilp->getDirDelimiter(); // initialize delimiter to dir sep slash - - // refresh list of available languages (EN will still be default) - BOOL found = TRUE; - BOOL found_en_us = FALSE; - std::string language_directory; - std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim - mLanguageSelection->removeall(); // clear out anything temporarily in list from XML - - LLDirIterator iter(xui_dir, "*"); - while(found) // for every directory - { - if((found = iter.next(language_directory))) // get next directory - { - std::string full_path = gDirUtilp->add(xui_dir, language_directory); - if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it - { - continue; - } - - if(strncmp("template",language_directory.c_str(),8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory - { - if(!strncmp("en",language_directory.c_str(),5)) // remember if we've seen en, so we can make it default - { - found_en_us = TRUE; - } - else - { - mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu - mLanguageSelection_2->add(std::string(language_directory)); - } - } - } - } - if(found_en_us) - { - mLanguageSelection->add(std::string("en"),ADD_TOP); // make en first item if we found it - mLanguageSelection_2->add(std::string("en"),ADD_TOP); - } - else - { - std::string warning = std::string("No EN localization found; check your XUI directories!"); - popupAndPrintWarning(warning); - } - mLanguageSelection->selectFirstItem(); // select the first item - mLanguageSelection_2->selectFirstItem(); - - refreshList(); // refresh the list of available floaters - - return TRUE; + LLPanel* main_panel_tmp = getChild("main_panel"); // get a pointer to the main panel in order to... + mFileList = main_panel_tmp->getChild("name_list"); // save pointer to file list + // Double-click opens the floater, for convenience + mFileList->setDoubleClickCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); + + setDefaultBtn("display_floater"); + // get pointers to buttons and link to callbacks + mLanguageSelection = main_panel_tmp->getChild("language_select_combo"); + mLanguageSelection->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); + mLanguageSelection_2 = main_panel_tmp->getChild("language_select_combo_2"); + mLanguageSelection_2->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); + LLPanel* editor_panel_tmp = main_panel_tmp->getChild("editor_panel"); + mDisplayFloaterBtn = main_panel_tmp->getChild("display_floater"); + mDisplayFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); + mDisplayFloaterBtn_2 = main_panel_tmp->getChild("display_floater_2"); + mDisplayFloaterBtn_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, SECONDARY_FLOATER)); + mToggleOverlapButton = main_panel_tmp->getChild("toggle_overlap_panel"); + mToggleOverlapButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleOverlapping, this)); + mCloseOtherButton = main_panel_tmp->getChild("close_displayed_floater"); + mCloseOtherButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, PRIMARY_FLOATER)); + mCloseOtherButton_2 = main_panel_tmp->getChild("close_displayed_floater_2"); + mCloseOtherButton_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, SECONDARY_FLOATER)); + mEditFloaterBtn = main_panel_tmp->getChild("edit_floater"); + mEditFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickEditFloater, this)); + mExecutableBrowseButton = editor_panel_tmp->getChild("browse_for_executable"); + LLPanel* vlt_panel_tmp = main_panel_tmp->getChild("vlt_panel"); + mExecutableBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForEditor, this)); + mDiffBrowseButton = vlt_panel_tmp->getChild("browse_for_vlt_diffs"); + mDiffBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForDiffs, this)); + mToggleHighlightButton = vlt_panel_tmp->getChild("toggle_vlt_diff_highlight"); + mToggleHighlightButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleDiffHighlighting, this)); + main_panel_tmp->getChild("save_floater")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveFloater, this, PRIMARY_FLOATER)); + main_panel_tmp->getChild("save_all_floaters")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveAll, this, PRIMARY_FLOATER)); + + getChild("export_schema")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickExportSchema, this)); + getChild("show_rectangles")->setCommitCallback( + boost::bind(&LLFloaterUIPreview::onClickShowRectangles, this, _2)); + + // get pointers to text fields + mEditorPathTextBox = editor_panel_tmp->getChild("executable_path_field"); + mEditorArgsTextBox = editor_panel_tmp->getChild("executable_args_field"); + mDiffPathTextBox = vlt_panel_tmp->getChild("vlt_diff_path_field"); + + // *HACK: restored saved editor path and args to textfields + mEditorPathTextBox->setText(mSavedEditorPath); + mEditorArgsTextBox->setText(mSavedEditorArgs); + mDiffPathTextBox->setText(mSavedDiffPath); + + // Set up overlap panel + mOverlapPanel = getChild("overlap_panel"); + + getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); + + mDelim = gDirUtilp->getDirDelimiter(); // initialize delimiter to dir sep slash + + // refresh list of available languages (EN will still be default) + BOOL found = TRUE; + BOOL found_en_us = FALSE; + std::string language_directory; + std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim + mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + + LLDirIterator iter(xui_dir, "*"); + while(found) // for every directory + { + if((found = iter.next(language_directory))) // get next directory + { + std::string full_path = gDirUtilp->add(xui_dir, language_directory); + if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it + { + continue; + } + + if(strncmp("template",language_directory.c_str(),8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory + { + if(!strncmp("en",language_directory.c_str(),5)) // remember if we've seen en, so we can make it default + { + found_en_us = TRUE; + } + else + { + mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu + mLanguageSelection_2->add(std::string(language_directory)); + } + } + } + } + if(found_en_us) + { + mLanguageSelection->add(std::string("en"),ADD_TOP); // make en first item if we found it + mLanguageSelection_2->add(std::string("en"),ADD_TOP); + } + else + { + std::string warning = std::string("No EN localization found; check your XUI directories!"); + popupAndPrintWarning(warning); + } + mLanguageSelection->selectFirstItem(); // select the first item + mLanguageSelection_2->selectFirstItem(); + + refreshList(); // refresh the list of available floaters + + return TRUE; } // Callback for language combo box selection: refresh current floater when you change languages void LLFloaterUIPreview::onLanguageComboSelect(LLUICtrl* ctrl) { - LLComboBox* caller = dynamic_cast(ctrl); - if (!caller) - return; - if(caller->getName() == std::string("language_select_combo")) - { - if(mDisplayedFloater) - { - onClickCloseDisplayedFloater(PRIMARY_FLOATER); - displayFloater(TRUE,1); - } - } - else - { - if(mDisplayedFloater_2) - { - onClickCloseDisplayedFloater(PRIMARY_FLOATER); - displayFloater(TRUE,2); // *TODO: make take an arg - } - } + LLComboBox* caller = dynamic_cast(ctrl); + if (!caller) + return; + if(caller->getName() == std::string("language_select_combo")) + { + if(mDisplayedFloater) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + displayFloater(TRUE,1); + } + } + else + { + if(mDisplayedFloater_2) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + displayFloater(TRUE,2); // *TODO: make take an arg + } + } } void LLFloaterUIPreview::onClickExportSchema() { - //NOTE: schema generation not complete - //gViewerWindow->setCursor(UI_CURSOR_WAIT); - //std::string template_path = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "xui", "schema"); - - //typedef LLWidgetTypeRegistry::Registrar::registry_map_t::const_iterator registry_it; - //registry_it end_it = LLWidgetTypeRegistry::defaultRegistrar().endItems(); - //for(registry_it it = LLWidgetTypeRegistry::defaultRegistrar().beginItems(); - // it != end_it; - // ++it) - //{ - // std::string widget_name = it->first; - // const LLInitParam::BaseBlock& block = - // (*LLDefaultParamBlockRegistry::instance().getValue(*LLWidgetTypeRegistry::instance().getValue(widget_name)))(); - // LLXMLNodePtr root_nodep = new LLXMLNode(); - // LLRNGWriter().writeRNG(widget_name, root_nodep, block, "http://www.lindenlab.com/xui"); - - // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); - - // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), "w"); - // { - // LLXMLNode::writeHeaderToFile(rng_file); - // const bool use_type_decorations = false; - // root_nodep->writeToFile(rng_file, std::string(), use_type_decorations); - // } - // fclose(rng_file); - //} - //gViewerWindow->setCursor(UI_CURSOR_ARROW); + //NOTE: schema generation not complete + //gViewerWindow->setCursor(UI_CURSOR_WAIT); + //std::string template_path = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "xui", "schema"); + + //typedef LLWidgetTypeRegistry::Registrar::registry_map_t::const_iterator registry_it; + //registry_it end_it = LLWidgetTypeRegistry::defaultRegistrar().endItems(); + //for(registry_it it = LLWidgetTypeRegistry::defaultRegistrar().beginItems(); + // it != end_it; + // ++it) + //{ + // std::string widget_name = it->first; + // const LLInitParam::BaseBlock& block = + // (*LLDefaultParamBlockRegistry::instance().getValue(*LLWidgetTypeRegistry::instance().getValue(widget_name)))(); + // LLXMLNodePtr root_nodep = new LLXMLNode(); + // LLRNGWriter().writeRNG(widget_name, root_nodep, block, "http://www.lindenlab.com/xui"); + + // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); + + // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), "w"); + // { + // LLXMLNode::writeHeaderToFile(rng_file); + // const bool use_type_decorations = false; + // root_nodep->writeToFile(rng_file, std::string(), use_type_decorations); + // } + // fclose(rng_file); + //} + //gViewerWindow->setCursor(UI_CURSOR_ARROW); } void LLFloaterUIPreview::onClickShowRectangles(const LLSD& data) { - LLPreviewedFloater::sShowRectangles = data.asBoolean(); + LLPreviewedFloater::sShowRectangles = data.asBoolean(); } // Close click handler -- delete my displayed floater if it exists void LLFloaterUIPreview::onClose(bool app_quitting) { - if(!app_quitting && mDisplayedFloater) - { - onClickCloseDisplayedFloater(PRIMARY_FLOATER); - onClickCloseDisplayedFloater(SECONDARY_FLOATER); - delete mDisplayedFloater; - mDisplayedFloater = NULL; - delete mDisplayedFloater_2; - mDisplayedFloater_2 = NULL; - } + if(!app_quitting && mDisplayedFloater) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + onClickCloseDisplayedFloater(SECONDARY_FLOATER); + delete mDisplayedFloater; + mDisplayedFloater = NULL; + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } } // Error handling (to avoid code repetition) // *TODO: this is currently unlocalized. Add to alerts/notifications.xml, someday, maybe. void LLFloaterUIPreview::popupAndPrintWarning(const std::string& warning) { - LL_WARNS() << warning << LL_ENDL; - LLSD args; - args["MESSAGE"] = warning; - LLNotificationsUtil::add("GenericAlert", args); + LL_WARNS() << warning << LL_ENDL; + LLSD args; + args["MESSAGE"] = warning; + LLNotificationsUtil::add("GenericAlert", args); } // Get localization string from drop-down menu std::string LLFloaterUIPreview::getLocStr(S32 ID) { - if(ID == 1) - { - return mLanguageSelection->getSelectedItemLabel(0); - } - else - { - return mLanguageSelection_2->getSelectedItemLabel(0); - } + if(ID == 1) + { + return mLanguageSelection->getSelectedItemLabel(0); + } + else + { + return mLanguageSelection_2->getSelectedItemLabel(0); + } } // Get localized directory (build path from data directory to XUI files, substituting localization string in for language) std::string LLFloaterUIPreview::getLocalizedDirectory() { - return get_xui_dir() + (getLocStr(1)) + mDelim; // e.g. "C:/Code/guipreview/indra/newview/skins/xui/en/"; + return get_xui_dir() + (getLocStr(1)) + mDelim; // e.g. "C:/Code/guipreview/indra/newview/skins/xui/en/"; } // Refresh the list of floaters by doing a directory traverse for XML XUI floater files // Could be used to grab any specific language's list of compatible floaters, but currently it's just used to get all of them void LLFloaterUIPreview::refreshList() { - // Note: the mask doesn't seem to accept regular expressions, so there need to be two directory searches here - mFileList->clearRows(); // empty list - std::string name; - BOOL found = TRUE; - - LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); - while(found) // for every floater file that matches the pattern - { - if((found = floater_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); - while(found) // for every inspector file that matches the pattern - { - if((found = inspect_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); - while(found) // for every menu file that matches the pattern - { - if((found = menu_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); - while(found) // for every panel file that matches the pattern - { - if((found = panel_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - found = TRUE; - - LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); - while(found) // for every sidepanel file that matches the pattern - { - if((found = sidepanel_iter.next(name))) // get next file matching pattern - { - addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) - } - } - - if(!mFileList->isEmpty()) // if there were any matching files, just select the first one (so we don't have to worry about disabling buttons when no entry is selected) - { - mFileList->selectFirstItem(); - } + // Note: the mask doesn't seem to accept regular expressions, so there need to be two directory searches here + mFileList->clearRows(); // empty list + std::string name; + BOOL found = TRUE; + + LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); + while(found) // for every floater file that matches the pattern + { + if((found = floater_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); + while(found) // for every inspector file that matches the pattern + { + if((found = inspect_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); + while(found) // for every menu file that matches the pattern + { + if((found = menu_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); + while(found) // for every panel file that matches the pattern + { + if((found = panel_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + + LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); + while(found) // for every sidepanel file that matches the pattern + { + if((found = sidepanel_iter.next(name))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + + if(!mFileList->isEmpty()) // if there were any matching files, just select the first one (so we don't have to worry about disabling buttons when no entry is selected) + { + mFileList->selectFirstItem(); + } } // Add a single entry to the list of available floaters // Note: no deduplification (shouldn't be necessary) void LLFloaterUIPreview::addFloaterEntry(const std::string& path) { - LLUUID* entry_id = new LLUUID(); // create a new UUID - entry_id->generate(path); - const LLUUID& entry_id_ref = *entry_id; // get a reference to the UUID for the LLSD block - - // fill LLSD column entry: initialize row/col structure - LLSD row; - row["id"] = entry_id_ref; - LLSD& columns = row["columns"]; - - // Get name of floater: - LLXmlTree xml_tree; - std::string full_path = getLocalizedDirectory() + path; // get full path - BOOL success = xml_tree.parseFile(full_path.c_str(), TRUE); // parse xml - std::string entry_name; - std::string entry_title; - if(success) - { - // get root (or error handle) - LLXmlTreeNode* root_floater = xml_tree.getRoot(); - if (!root_floater) - { - std::string warning = std::string("No root node found in XUI file: ") + path; - popupAndPrintWarning(warning); - return; - } - - // get name - root_floater->getAttributeString("name",entry_name); - if(std::string("") == entry_name) - { - entry_name = "Error: unable to load " + std::string(path); // set to error state if load fails - } - - // get title - root_floater->getAttributeString("title",entry_title); // some don't have a title, and some have title = "(unknown)", so just leave it blank if it fails - } - else - { - std::string warning = std::string("Unable to parse XUI file: ") + path; // error handling - popupAndPrintWarning(warning); - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } - return; - } - - // Fill floater title column - columns[0]["column"] = "title_column"; - columns[0]["type"] = "text"; - columns[0]["value"] = entry_title; - - // Fill floater path column - columns[1]["column"] = "file_column"; - columns[1]["type"] = "text"; - columns[1]["value"] = std::string(path); - - // Fill floater name column - columns[2]["column"] = "top_level_node_column"; - columns[2]["type"] = "text"; - columns[2]["value"] = entry_name; - - mFileList->addElement(row); // actually add to list + LLUUID* entry_id = new LLUUID(); // create a new UUID + entry_id->generate(path); + const LLUUID& entry_id_ref = *entry_id; // get a reference to the UUID for the LLSD block + + // fill LLSD column entry: initialize row/col structure + LLSD row; + row["id"] = entry_id_ref; + LLSD& columns = row["columns"]; + + // Get name of floater: + LLXmlTree xml_tree; + std::string full_path = getLocalizedDirectory() + path; // get full path + BOOL success = xml_tree.parseFile(full_path.c_str(), TRUE); // parse xml + std::string entry_name; + std::string entry_title; + if(success) + { + // get root (or error handle) + LLXmlTreeNode* root_floater = xml_tree.getRoot(); + if (!root_floater) + { + std::string warning = std::string("No root node found in XUI file: ") + path; + popupAndPrintWarning(warning); + return; + } + + // get name + root_floater->getAttributeString("name",entry_name); + if(std::string("") == entry_name) + { + entry_name = "Error: unable to load " + std::string(path); // set to error state if load fails + } + + // get title + root_floater->getAttributeString("title",entry_title); // some don't have a title, and some have title = "(unknown)", so just leave it blank if it fails + } + else + { + std::string warning = std::string("Unable to parse XUI file: ") + path; // error handling + popupAndPrintWarning(warning); + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + return; + } + + // Fill floater title column + columns[0]["column"] = "title_column"; + columns[0]["type"] = "text"; + columns[0]["value"] = entry_title; + + // Fill floater path column + columns[1]["column"] = "file_column"; + columns[1]["type"] = "text"; + columns[1]["value"] = std::string(path); + + // Fill floater name column + columns[2]["column"] = "top_level_node_column"; + columns[2]["type"] = "text"; + columns[2]["value"] = entry_name; + + mFileList->addElement(row); // actually add to list } // Respond to button click to display/refresh currently-selected floater void LLFloaterUIPreview::onClickDisplayFloater(S32 caller_id) { - displayFloater(TRUE, caller_id); + displayFloater(TRUE, caller_id); } // Saves the current floater/panel void LLFloaterUIPreview::onClickSaveFloater(S32 caller_id) { - displayFloater(TRUE, caller_id); - popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); + displayFloater(TRUE, caller_id); + popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); } // Saves all floater/panels void LLFloaterUIPreview::onClickSaveAll(S32 caller_id) { - int listSize = mFileList->getItemCount(); - - for (int index = 0; index < listSize; index++) - { - mFileList->selectNthItem(index); - displayFloater(TRUE, caller_id); - } - popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); + int listSize = mFileList->getItemCount(); + + for (int index = 0; index < listSize; index++) + { + mFileList->selectNthItem(index); + displayFloater(TRUE, caller_id); + } + popupAndPrintWarning("Save-floater functionality removed, use XML schema to clean up XUI files"); } // Actually display the floater @@ -799,224 +799,224 @@ void LLFloaterUIPreview::onClickSaveAll(S32 caller_id) // otherwise, we get an infinite loop as the live file keeps recreating itself. That means this function is generally called twice. void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID) { - // Convince UI that we're in a different language (the one selected on the drop-down menu) - LLLocalizationResetForcer reset_forcer(this, ID); // save old language in reset forcer object (to be reset upon destruction when it falls out of scope) - - LLPreviewedFloater** floaterp = (ID == 1 ? &(mDisplayedFloater) : &(mDisplayedFloater_2)); - if(ID == 1) - { - BOOL floater_already_open = mDisplayedFloater != NULL; - if(floater_already_open) // if we are already displaying a floater - { - mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; // save floater's last known position to put the new one there - mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; - delete mDisplayedFloater; // delete it (this closes it too) - mDisplayedFloater = NULL; // and reset the pointer - } - } - else - { - if(mDisplayedFloater_2 != NULL) - { - delete mDisplayedFloater_2; - mDisplayedFloater_2 = NULL; - } - } - - std::string path = mFileList->getSelectedItemLabel(1); // get the path of the currently-selected floater - if(std::string("") == path) // if no item is selected - { - return; // ignore click (this can only happen with empty list; otherwise an item is always selected) - } - - LLFloater::Params p(LLFloater::getDefaultParams()); - p.min_height=p.header_height; - p.min_width=10; - - *floaterp = new LLPreviewedFloater(this, p); - - if(!strncmp(path.c_str(),"floater_",8) - || !strncmp(path.c_str(), "inspect_", 8)) // if it's a floater - { - (*floaterp)->buildFromFile(path); // just build it - (*floaterp)->openFloater((*floaterp)->getKey()); - (*floaterp)->setCanResize((*floaterp)->isResizable()); - } - else if (!strncmp(path.c_str(),"menu_",5)) // if it's a menu - { - // former 'save' processing excised - } - else // if it is a panel... - { - (*floaterp)->setCanResize(true); - - const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); - S32 floater_header_size = floater_params.header_height; - - LLPanel::Params panel_params; - LLPanel* panel = LLUICtrlFactory::create(panel_params); // create a new panel - - panel->buildFromFile(path); // build it - panel->setOrigin(2,2); // reset its origin point so it's not offset by -left or other XUI attributes - (*floaterp)->setTitle(path); // use the file name as its title, since panels have no guaranteed meaningful name attribute - panel->setUseBoundingRect(TRUE); // enable the use of its outer bounding rect (normally disabled because it's O(n) on the number of sub-elements) - panel->updateBoundingRect(); // update bounding rect - LLRect bounding_rect = panel->getBoundingRect(); // get the bounding rect - LLRect new_rect = panel->getRect(); // get the panel's rect - new_rect.unionWith(bounding_rect); // union them to make sure we get the biggest one possible - LLRect floater_rect = new_rect; - floater_rect.stretch(4, 4); - (*floaterp)->reshape(floater_rect.getWidth(), floater_rect.getHeight() + floater_header_size); // reshape floater to match the union rect's dimensions - panel->reshape(new_rect.getWidth(), new_rect.getHeight()); // reshape panel to match the union rect's dimensions as well (both are needed) - (*floaterp)->addChild(panel); // add panel as child - (*floaterp)->openFloater(); // open floater (needed?) - } - - if(ID == 1) - { - (*floaterp)->setOrigin(mLastDisplayedX, mLastDisplayedY); - } - - // *HACK: Remove ability to close it; if you close it, its destructor gets called, but we don't know it's null and try to delete it again, - // resulting in a double free - (*floaterp)->setCanClose(FALSE); - - if(ID == 1) - { - mCloseOtherButton->setEnabled(TRUE); // enable my floater's close button - } - else - { - mCloseOtherButton_2->setEnabled(TRUE); - } - - // Add localization to title so user knows whether it's localized or defaulted to en - std::string full_path = getLocalizedDirectory() + path; - std::string floater_lang = "EN"; - llstat dummy; - if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist - { - floater_lang = getLocStr(ID); - } - std::string new_title = (*floaterp)->getTitle() + std::string(" [") + floater_lang + - (ID == 1 ? " - Primary" : " - Secondary") + std::string("]"); - (*floaterp)->setTitle(new_title); - - (*floaterp)->center(); - addDependentFloater(*floaterp); - - if(click && ID == 1) - { - // set up live file to track it - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } - mLiveFile = new LLGUIPreviewLiveFile(std::string(full_path.c_str()),std::string(path.c_str()),this); - mLiveFile->checkAndReload(); - mLiveFile->addToEventTimer(); - } - - if(ID == 1) - { - mToggleOverlapButton->setEnabled(TRUE); - } - - if(LLView::sHighlightingDiffs && click && ID == 1) - { - highlightChangedElements(); - } - - if(ID == 1) - { - mOverlapPanel->mOverlapMap.clear(); - LLView::sPreviewClickedElement = NULL; // stop overlapping elements from drawing - mOverlapPanel->mLastClickedElement = NULL; - findOverlapsInChildren((LLView*)mDisplayedFloater); - - // highlight and enable them - if(mHighlightingOverlaps) - { - for(LLOverlapPanel::OverlapMap::iterator iter = mOverlapPanel->mOverlapMap.begin(); iter != mOverlapPanel->mOverlapMap.end(); ++iter) - { - LLView* viewp = iter->first; - LLView::sPreviewHighlightedElements.insert(viewp); - } - } - else if(LLView::sHighlightingDiffs) - { - highlightChangedElements(); - } - } - - // NOTE: language is reset here automatically when the reset forcer object falls out of scope (see header for details) + // Convince UI that we're in a different language (the one selected on the drop-down menu) + LLLocalizationResetForcer reset_forcer(this, ID); // save old language in reset forcer object (to be reset upon destruction when it falls out of scope) + + LLPreviewedFloater** floaterp = (ID == 1 ? &(mDisplayedFloater) : &(mDisplayedFloater_2)); + if(ID == 1) + { + BOOL floater_already_open = mDisplayedFloater != NULL; + if(floater_already_open) // if we are already displaying a floater + { + mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; // save floater's last known position to put the new one there + mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; + delete mDisplayedFloater; // delete it (this closes it too) + mDisplayedFloater = NULL; // and reset the pointer + } + } + else + { + if(mDisplayedFloater_2 != NULL) + { + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } + } + + std::string path = mFileList->getSelectedItemLabel(1); // get the path of the currently-selected floater + if(std::string("") == path) // if no item is selected + { + return; // ignore click (this can only happen with empty list; otherwise an item is always selected) + } + + LLFloater::Params p(LLFloater::getDefaultParams()); + p.min_height=p.header_height; + p.min_width=10; + + *floaterp = new LLPreviewedFloater(this, p); + + if(!strncmp(path.c_str(),"floater_",8) + || !strncmp(path.c_str(), "inspect_", 8)) // if it's a floater + { + (*floaterp)->buildFromFile(path); // just build it + (*floaterp)->openFloater((*floaterp)->getKey()); + (*floaterp)->setCanResize((*floaterp)->isResizable()); + } + else if (!strncmp(path.c_str(),"menu_",5)) // if it's a menu + { + // former 'save' processing excised + } + else // if it is a panel... + { + (*floaterp)->setCanResize(true); + + const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); + S32 floater_header_size = floater_params.header_height; + + LLPanel::Params panel_params; + LLPanel* panel = LLUICtrlFactory::create(panel_params); // create a new panel + + panel->buildFromFile(path); // build it + panel->setOrigin(2,2); // reset its origin point so it's not offset by -left or other XUI attributes + (*floaterp)->setTitle(path); // use the file name as its title, since panels have no guaranteed meaningful name attribute + panel->setUseBoundingRect(TRUE); // enable the use of its outer bounding rect (normally disabled because it's O(n) on the number of sub-elements) + panel->updateBoundingRect(); // update bounding rect + LLRect bounding_rect = panel->getBoundingRect(); // get the bounding rect + LLRect new_rect = panel->getRect(); // get the panel's rect + new_rect.unionWith(bounding_rect); // union them to make sure we get the biggest one possible + LLRect floater_rect = new_rect; + floater_rect.stretch(4, 4); + (*floaterp)->reshape(floater_rect.getWidth(), floater_rect.getHeight() + floater_header_size); // reshape floater to match the union rect's dimensions + panel->reshape(new_rect.getWidth(), new_rect.getHeight()); // reshape panel to match the union rect's dimensions as well (both are needed) + (*floaterp)->addChild(panel); // add panel as child + (*floaterp)->openFloater(); // open floater (needed?) + } + + if(ID == 1) + { + (*floaterp)->setOrigin(mLastDisplayedX, mLastDisplayedY); + } + + // *HACK: Remove ability to close it; if you close it, its destructor gets called, but we don't know it's null and try to delete it again, + // resulting in a double free + (*floaterp)->setCanClose(FALSE); + + if(ID == 1) + { + mCloseOtherButton->setEnabled(TRUE); // enable my floater's close button + } + else + { + mCloseOtherButton_2->setEnabled(TRUE); + } + + // Add localization to title so user knows whether it's localized or defaulted to en + std::string full_path = getLocalizedDirectory() + path; + std::string floater_lang = "EN"; + llstat dummy; + if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist + { + floater_lang = getLocStr(ID); + } + std::string new_title = (*floaterp)->getTitle() + std::string(" [") + floater_lang + + (ID == 1 ? " - Primary" : " - Secondary") + std::string("]"); + (*floaterp)->setTitle(new_title); + + (*floaterp)->center(); + addDependentFloater(*floaterp); + + if(click && ID == 1) + { + // set up live file to track it + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + mLiveFile = new LLGUIPreviewLiveFile(std::string(full_path.c_str()),std::string(path.c_str()),this); + mLiveFile->checkAndReload(); + mLiveFile->addToEventTimer(); + } + + if(ID == 1) + { + mToggleOverlapButton->setEnabled(TRUE); + } + + if(LLView::sHighlightingDiffs && click && ID == 1) + { + highlightChangedElements(); + } + + if(ID == 1) + { + mOverlapPanel->mOverlapMap.clear(); + LLView::sPreviewClickedElement = NULL; // stop overlapping elements from drawing + mOverlapPanel->mLastClickedElement = NULL; + findOverlapsInChildren((LLView*)mDisplayedFloater); + + // highlight and enable them + if(mHighlightingOverlaps) + { + for(LLOverlapPanel::OverlapMap::iterator iter = mOverlapPanel->mOverlapMap.begin(); iter != mOverlapPanel->mOverlapMap.end(); ++iter) + { + LLView* viewp = iter->first; + LLView::sPreviewHighlightedElements.insert(viewp); + } + } + else if(LLView::sHighlightingDiffs) + { + highlightChangedElements(); + } + } + + // NOTE: language is reset here automatically when the reset forcer object falls out of scope (see header for details) } // Respond to button click to edit currently-selected floater void LLFloaterUIPreview::onClickEditFloater() { - // Determine file to edit. - std::string file_path; - { - std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater - if (file_name.empty()) // if no item is selected - { - LL_WARNS() << "No file selected" << LL_ENDL; - return; // ignore click - } - file_path = getLocalizedDirectory() + file_name; - - // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) - llstat dummy; - if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist - { - popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead."); - file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default - } - } - - // Set the editor command. - std::string cmd_override; - { - std::string bin = mEditorPathTextBox->getText(); - if (!bin.empty()) - { - // surround command with double quotes for the case if the path contains spaces - if (bin.find("\"") == std::string::npos) - { - bin = "\"" + bin + "\""; - } - - std::string args = mEditorArgsTextBox->getText(); - cmd_override = bin + " " + args; - } - } - - LLExternalEditor::EErrorCode status = mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override); - if (status != LLExternalEditor::EC_SUCCESS) - { - std::string warning; - - if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error. - { - warning = getString("ExternalEditorNotSet"); - } - else - { - warning = LLExternalEditor::getErrorMessage(status); - } - - popupAndPrintWarning(warning); - return; - } - - // Run the editor. - if (mExternalEditor.run(file_path) != LLExternalEditor::EC_SUCCESS) - { - popupAndPrintWarning(LLExternalEditor::getErrorMessage(status)); - return; - } + // Determine file to edit. + std::string file_path; + { + std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater + if (file_name.empty()) // if no item is selected + { + LL_WARNS() << "No file selected" << LL_ENDL; + return; // ignore click + } + file_path = getLocalizedDirectory() + file_name; + + // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) + llstat dummy; + if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist + { + popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead."); + file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default + } + } + + // Set the editor command. + std::string cmd_override; + { + std::string bin = mEditorPathTextBox->getText(); + if (!bin.empty()) + { + // surround command with double quotes for the case if the path contains spaces + if (bin.find("\"") == std::string::npos) + { + bin = "\"" + bin + "\""; + } + + std::string args = mEditorArgsTextBox->getText(); + cmd_override = bin + " " + args; + } + } + + LLExternalEditor::EErrorCode status = mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override); + if (status != LLExternalEditor::EC_SUCCESS) + { + std::string warning; + + if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error. + { + warning = getString("ExternalEditorNotSet"); + } + else + { + warning = LLExternalEditor::getErrorMessage(status); + } + + popupAndPrintWarning(warning); + return; + } + + // Run the editor. + if (mExternalEditor.run(file_path) != LLExternalEditor::EC_SUCCESS) + { + popupAndPrintWarning(LLExternalEditor::getErrorMessage(status)); + return; + } } // Respond to button click to browse for an executable with which to edit XML files @@ -1028,398 +1028,398 @@ void LLFloaterUIPreview::onClickBrowseForEditor() void LLFloaterUIPreview::getExecutablePath(const std::vector& filenames) { - // put the selected path into text field - const std::string chosen_path = filenames[0]; - std::string executable_path = chosen_path; + // put the selected path into text field + const std::string chosen_path = filenames[0]; + std::string executable_path = chosen_path; #if LL_DARWIN - // on Mac, if it's an application bundle, figure out the actual path from the Info.plist file - CFStringRef path_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, chosen_path.c_str(), kCFStringEncodingMacRoman); // get path as a CFStringRef - CFURLRef path_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_cfstr, kCFURLPOSIXPathStyle, TRUE); // turn it into a CFURLRef - CFBundleRef chosen_bundle = CFBundleCreate(kCFAllocatorDefault, path_url); // get a handle for the bundle - if(NULL != chosen_bundle) - { - CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(chosen_bundle); // get the bundle's dictionary - if(NULL != bundleInfoDict) - { - CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) - int max_file_length = 256; // (max file name length is 255 in OSX) - char executable_buf[max_file_length]; - if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* - { - executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path - } - else - { - std::string warning = "Unable to get CString from CFString for executable path"; - popupAndPrintWarning(warning); - } - } - else - { - std::string warning = "Unable to get bundle info dictionary from application bundle"; - popupAndPrintWarning(warning); - } - } - else - { - if(-1 != executable_path.find(".app")) // only warn if this path actually had ".app" in it, i.e. it probably just wasn'nt an app bundle and that's okay - { - std::string warning = std::string("Unable to get bundle from path \"") + chosen_path + std::string("\""); - popupAndPrintWarning(warning); - } - } + // on Mac, if it's an application bundle, figure out the actual path from the Info.plist file + CFStringRef path_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, chosen_path.c_str(), kCFStringEncodingMacRoman); // get path as a CFStringRef + CFURLRef path_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_cfstr, kCFURLPOSIXPathStyle, TRUE); // turn it into a CFURLRef + CFBundleRef chosen_bundle = CFBundleCreate(kCFAllocatorDefault, path_url); // get a handle for the bundle + if(NULL != chosen_bundle) + { + CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(chosen_bundle); // get the bundle's dictionary + if(NULL != bundleInfoDict) + { + CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) + int max_file_length = 256; // (max file name length is 255 in OSX) + char executable_buf[max_file_length]; + if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* + { + executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path + } + else + { + std::string warning = "Unable to get CString from CFString for executable path"; + popupAndPrintWarning(warning); + } + } + else + { + std::string warning = "Unable to get bundle info dictionary from application bundle"; + popupAndPrintWarning(warning); + } + } + else + { + if(-1 != executable_path.find(".app")) // only warn if this path actually had ".app" in it, i.e. it probably just wasn'nt an app bundle and that's okay + { + std::string warning = std::string("Unable to get bundle from path \"") + chosen_path + std::string("\""); + popupAndPrintWarning(warning); + } + } #endif - mEditorPathTextBox->setText(std::string(executable_path)); // copy the path to the executable to the textfield for display and later fetching + mEditorPathTextBox->setText(std::string(executable_path)); // copy the path to the executable to the textfield for display and later fetching } // Respond to button click to browse for a VLT-generated diffs file void LLFloaterUIPreview::onClickBrowseForDiffs() { - // create load dialog box + // create load dialog box LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterUIPreview::getDiffsFilePath(const std::vector& filenames) { - // put the selected path into text field - const std::string chosen_path = filenames[0]; - mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching - if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file - { - onClickToggleDiffHighlighting(); - onClickToggleDiffHighlighting(); - } + // put the selected path into text field + const std::string chosen_path = filenames[0]; + mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching + if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file + { + onClickToggleDiffHighlighting(); + onClickToggleDiffHighlighting(); + } } void LLFloaterUIPreview::onClickToggleDiffHighlighting() { - if(mHighlightingOverlaps) - { - onClickToggleOverlapping(); - mToggleOverlapButton->toggleState(); - } - - LLView::sPreviewHighlightedElements.clear(); // clear lists first - mDiffsMap.clear(); - mFileList->clearHighlightedItems(); - - if(LLView::sHighlightingDiffs) // Turning highlighting off - { - LLView::sHighlightingDiffs = !sHighlightingDiffs; - return; - } - else // Turning highlighting on - { - // Get the file and make sure it exists - std::string path_in_textfield = mDiffPathTextBox->getText(); // get file path - BOOL error = FALSE; - - if(std::string("") == path_in_textfield) // check for blank file - { - std::string warning = "Unable to highlight differences because no file was provided; fill in the relevant text field"; - popupAndPrintWarning(warning); - error = TRUE; - } - - llstat dummy; - if(LLFile::stat(path_in_textfield.c_str(), &dummy) && !error) // check if the file exists (empty check is reduntant but useful for the informative error message) - { - std::string warning = std::string("Unable to highlight differences because an invalid path to a difference file was provided:\"") + path_in_textfield + "\""; - popupAndPrintWarning(warning); - error = TRUE; - } - - // Build a list of changed elements as given by the XML - std::list changed_element_names; - LLXmlTree xml_tree; - BOOL success = xml_tree.parseFile(path_in_textfield.c_str(), TRUE); - - if(success && !error) - { - LLXmlTreeNode* root_floater = xml_tree.getRoot(); - if(!strncmp("XuiDelta",root_floater->getName().c_str(),9)) - { - for (LLXmlTreeNode* child = root_floater->getFirstChild(); // get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) - child != NULL; - child = root_floater->getNextChild()) // get child for next iteration - { - if(!strncmp("file",child->getName().c_str(),5)) - { - scanDiffFile(child); - } - else if(!strncmp("error",child->getName().c_str(),6)) - { - std::string error_file, error_message; - child->getAttributeString("filename",error_file); - child->getAttributeString("message",error_message); - if(mDiffsMap.find(error_file) != mDiffsMap.end()) - { - mDiffsMap.insert(std::make_pair(error_file,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); - } - mDiffsMap[error_file].second->push_back(error_message); - } - else - { - std::string warning = std::string("Child was neither a file or an error, but rather the following:\"") + std::string(child->getName()) + "\""; - popupAndPrintWarning(warning); - error = TRUE; - break; - } - } - } - else - { - std::string warning = std::string("Root node not named XuiDelta:\"") + path_in_textfield + "\""; - popupAndPrintWarning(warning); - error = TRUE; - } - } - else if(!error) - { - std::string warning = std::string("Unable to create tree from XML:\"") + path_in_textfield + "\""; - popupAndPrintWarning(warning); - error = TRUE; - } - - if(error) // if we encountered an error, reset the button to off - { - mToggleHighlightButton->setToggleState(FALSE); - } - else // only toggle if we didn't encounter an error - { - LLView::sHighlightingDiffs = !sHighlightingDiffs; - highlightChangedElements(); // *TODO: this is extraneous, right? - highlightChangedFiles(); // *TODO: this is extraneous, right? - } - } + if(mHighlightingOverlaps) + { + onClickToggleOverlapping(); + mToggleOverlapButton->toggleState(); + } + + LLView::sPreviewHighlightedElements.clear(); // clear lists first + mDiffsMap.clear(); + mFileList->clearHighlightedItems(); + + if(LLView::sHighlightingDiffs) // Turning highlighting off + { + LLView::sHighlightingDiffs = !sHighlightingDiffs; + return; + } + else // Turning highlighting on + { + // Get the file and make sure it exists + std::string path_in_textfield = mDiffPathTextBox->getText(); // get file path + BOOL error = FALSE; + + if(std::string("") == path_in_textfield) // check for blank file + { + std::string warning = "Unable to highlight differences because no file was provided; fill in the relevant text field"; + popupAndPrintWarning(warning); + error = TRUE; + } + + llstat dummy; + if(LLFile::stat(path_in_textfield.c_str(), &dummy) && !error) // check if the file exists (empty check is reduntant but useful for the informative error message) + { + std::string warning = std::string("Unable to highlight differences because an invalid path to a difference file was provided:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + + // Build a list of changed elements as given by the XML + std::list changed_element_names; + LLXmlTree xml_tree; + BOOL success = xml_tree.parseFile(path_in_textfield.c_str(), TRUE); + + if(success && !error) + { + LLXmlTreeNode* root_floater = xml_tree.getRoot(); + if(!strncmp("XuiDelta",root_floater->getName().c_str(),9)) + { + for (LLXmlTreeNode* child = root_floater->getFirstChild(); // get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) + child != NULL; + child = root_floater->getNextChild()) // get child for next iteration + { + if(!strncmp("file",child->getName().c_str(),5)) + { + scanDiffFile(child); + } + else if(!strncmp("error",child->getName().c_str(),6)) + { + std::string error_file, error_message; + child->getAttributeString("filename",error_file); + child->getAttributeString("message",error_message); + if(mDiffsMap.find(error_file) != mDiffsMap.end()) + { + mDiffsMap.insert(std::make_pair(error_file,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); + } + mDiffsMap[error_file].second->push_back(error_message); + } + else + { + std::string warning = std::string("Child was neither a file or an error, but rather the following:\"") + std::string(child->getName()) + "\""; + popupAndPrintWarning(warning); + error = TRUE; + break; + } + } + } + else + { + std::string warning = std::string("Root node not named XuiDelta:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + } + else if(!error) + { + std::string warning = std::string("Unable to create tree from XML:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + + if(error) // if we encountered an error, reset the button to off + { + mToggleHighlightButton->setToggleState(FALSE); + } + else // only toggle if we didn't encounter an error + { + LLView::sHighlightingDiffs = !sHighlightingDiffs; + highlightChangedElements(); // *TODO: this is extraneous, right? + highlightChangedFiles(); // *TODO: this is extraneous, right? + } + } } void LLFloaterUIPreview::scanDiffFile(LLXmlTreeNode* file_node) { - // Get file name - std::string file_name; - file_node->getAttributeString("name",file_name); - if(std::string("") == file_name) - { - std::string warning = std::string("Empty file name encountered in differences:\"") + file_name + "\""; - popupAndPrintWarning(warning); - return; - } - - // Get a list of changed elements - // Get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) - for (LLXmlTreeNode* child = file_node->getFirstChild(); child != NULL; child = file_node->getNextChild()) - { - if(!strncmp("delta",child->getName().c_str(),6)) - { - std::string id; - child->getAttributeString("id",id); - if(mDiffsMap.find(file_name) == mDiffsMap.end()) - { - mDiffsMap.insert(std::make_pair(file_name,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); - } - mDiffsMap[file_name].first->push_back(std::string(id.c_str())); - } - else - { - std::string warning = std::string("Child of file was not a delta, but rather the following:\"") + std::string(child->getName()) + "\""; - popupAndPrintWarning(warning); - return; - } - } + // Get file name + std::string file_name; + file_node->getAttributeString("name",file_name); + if(std::string("") == file_name) + { + std::string warning = std::string("Empty file name encountered in differences:\"") + file_name + "\""; + popupAndPrintWarning(warning); + return; + } + + // Get a list of changed elements + // Get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) + for (LLXmlTreeNode* child = file_node->getFirstChild(); child != NULL; child = file_node->getNextChild()) + { + if(!strncmp("delta",child->getName().c_str(),6)) + { + std::string id; + child->getAttributeString("id",id); + if(mDiffsMap.find(file_name) == mDiffsMap.end()) + { + mDiffsMap.insert(std::make_pair(file_name,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); + } + mDiffsMap[file_name].first->push_back(std::string(id.c_str())); + } + else + { + std::string warning = std::string("Child of file was not a delta, but rather the following:\"") + std::string(child->getName()) + "\""; + popupAndPrintWarning(warning); + return; + } + } } void LLFloaterUIPreview::highlightChangedElements() { - if(NULL == mLiveFile) - { - return; - } - - // Process differences first (we want their warnings to be shown underneath other warnings) - StringListPtr changed_element_paths; - DiffMap::iterator iterExists = mDiffsMap.find(mLiveFile->mFileName); - if(iterExists != mDiffsMap.end()) - { - changed_element_paths = mDiffsMap[mLiveFile->mFileName].first; // retrieve list of changed element paths from map - } - - for(std::list::iterator iter = changed_element_paths->begin(); iter != changed_element_paths->end(); ++iter) // for every changed element path - { - LLView* element = mDisplayedFloater; - if(!strncmp(iter->c_str(),".",1)) // if it's the root floater itself - { - continue; - } - - // Split element hierarchy path on period (*HACK: it's possible that the element name will have a period in it, in which case this won't work. See https://wiki.lindenlab.com/wiki/Viewer_Localization_Tool_Documentation.) - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("."); - tokenizer tokens(*iter, sep); - tokenizer::iterator token_iter; - BOOL failed = FALSE; - for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - element = element->findChild(*token_iter,FALSE); // try to find element: don't recur, and don't create if missing - - // if we still didn't find it... - if(NULL == element) - { - LL_INFOS() << "Unable to find element in XuiDelta file named \"" << *iter << "\" in file \"" << mLiveFile->mFileName << - "\". The element may no longer exist, the path may be incorrect, or it may not be a non-displayable element (not an LLView) such as a \"string\" type." << LL_ENDL; - failed = TRUE; - break; - } - } - - if(!failed) - { - // Now that we have a pointer to the actual element, add it to the list of elements to be highlighted - std::set::iterator iter2 = std::find(LLView::sPreviewHighlightedElements.begin(), LLView::sPreviewHighlightedElements.end(), element); - if(iter2 == LLView::sPreviewHighlightedElements.end()) - { - LLView::sPreviewHighlightedElements.insert(element); - } - } - } - - // Process errors second, so their warnings show up on top of other warnings - StringListPtr error_list; - if(iterExists != mDiffsMap.end()) - { - error_list = mDiffsMap[mLiveFile->mFileName].second; - } - for(std::list::iterator iter = error_list->begin(); iter != error_list->end(); ++iter) // for every changed element path - { - std::string warning = std::string("Error listed among differences. Filename: \"") + mLiveFile->mFileName + "\". Message: \"" + *iter + "\""; - popupAndPrintWarning(warning); - } + if(NULL == mLiveFile) + { + return; + } + + // Process differences first (we want their warnings to be shown underneath other warnings) + StringListPtr changed_element_paths; + DiffMap::iterator iterExists = mDiffsMap.find(mLiveFile->mFileName); + if(iterExists != mDiffsMap.end()) + { + changed_element_paths = mDiffsMap[mLiveFile->mFileName].first; // retrieve list of changed element paths from map + } + + for(std::list::iterator iter = changed_element_paths->begin(); iter != changed_element_paths->end(); ++iter) // for every changed element path + { + LLView* element = mDisplayedFloater; + if(!strncmp(iter->c_str(),".",1)) // if it's the root floater itself + { + continue; + } + + // Split element hierarchy path on period (*HACK: it's possible that the element name will have a period in it, in which case this won't work. See https://wiki.lindenlab.com/wiki/Viewer_Localization_Tool_Documentation.) + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + tokenizer tokens(*iter, sep); + tokenizer::iterator token_iter; + BOOL failed = FALSE; + for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + element = element->findChild(*token_iter,FALSE); // try to find element: don't recur, and don't create if missing + + // if we still didn't find it... + if(NULL == element) + { + LL_INFOS() << "Unable to find element in XuiDelta file named \"" << *iter << "\" in file \"" << mLiveFile->mFileName << + "\". The element may no longer exist, the path may be incorrect, or it may not be a non-displayable element (not an LLView) such as a \"string\" type." << LL_ENDL; + failed = TRUE; + break; + } + } + + if(!failed) + { + // Now that we have a pointer to the actual element, add it to the list of elements to be highlighted + std::set::iterator iter2 = std::find(LLView::sPreviewHighlightedElements.begin(), LLView::sPreviewHighlightedElements.end(), element); + if(iter2 == LLView::sPreviewHighlightedElements.end()) + { + LLView::sPreviewHighlightedElements.insert(element); + } + } + } + + // Process errors second, so their warnings show up on top of other warnings + StringListPtr error_list; + if(iterExists != mDiffsMap.end()) + { + error_list = mDiffsMap[mLiveFile->mFileName].second; + } + for(std::list::iterator iter = error_list->begin(); iter != error_list->end(); ++iter) // for every changed element path + { + std::string warning = std::string("Error listed among differences. Filename: \"") + mLiveFile->mFileName + "\". Message: \"" + *iter + "\""; + popupAndPrintWarning(warning); + } } void LLFloaterUIPreview::highlightChangedFiles() { - for(DiffMap::iterator iter = mDiffsMap.begin(); iter != mDiffsMap.end(); ++iter) // for every file listed in diffs - { - LLScrollListItem* item = mFileList->getItemByLabel(std::string(iter->first), FALSE, 1); - if(item) - { - item->setHighlighted(TRUE); - } - } + for(DiffMap::iterator iter = mDiffsMap.begin(); iter != mDiffsMap.end(); ++iter) // for every file listed in diffs + { + LLScrollListItem* item = mFileList->getItemByLabel(std::string(iter->first), FALSE, 1); + if(item) + { + item->setHighlighted(TRUE); + } + } } // Respond to button click to browse for an executable with which to edit XML files void LLFloaterUIPreview::onClickCloseDisplayedFloater(S32 caller_id) { - if(caller_id == PRIMARY_FLOATER) - { - mCloseOtherButton->setEnabled(FALSE); - mToggleOverlapButton->setEnabled(FALSE); - - if(mDisplayedFloater) - { - mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; - mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; - delete mDisplayedFloater; - mDisplayedFloater = NULL; - } - - if(mLiveFile) - { - delete mLiveFile; - mLiveFile = NULL; - } - - if(mToggleOverlapButton->getToggleState()) - { - mToggleOverlapButton->toggleState(); - onClickToggleOverlapping(); - } - - LLView::sPreviewClickedElement = NULL; // stop overlapping elements panel from drawing - mOverlapPanel->mLastClickedElement = NULL; - } - else - { - mCloseOtherButton_2->setEnabled(FALSE); - delete mDisplayedFloater_2; - mDisplayedFloater_2 = NULL; - } + if(caller_id == PRIMARY_FLOATER) + { + mCloseOtherButton->setEnabled(FALSE); + mToggleOverlapButton->setEnabled(FALSE); + + if(mDisplayedFloater) + { + mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; + mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; + delete mDisplayedFloater; + mDisplayedFloater = NULL; + } + + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + + if(mToggleOverlapButton->getToggleState()) + { + mToggleOverlapButton->toggleState(); + onClickToggleOverlapping(); + } + + LLView::sPreviewClickedElement = NULL; // stop overlapping elements panel from drawing + mOverlapPanel->mLastClickedElement = NULL; + } + else + { + mCloseOtherButton_2->setEnabled(FALSE); + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } } void append_view_tooltip(LLView* tooltip_view, std::string *tooltip_msg) { - LLRect rect = tooltip_view->getRect(); - LLRect parent_rect = tooltip_view->getParent()->getRect(); - S32 left = rect.mLeft; - // invert coordinate system for XUI top-left layout - S32 top = parent_rect.getHeight() - rect.mTop; - if (!tooltip_msg->empty()) - { - tooltip_msg->append("\n"); - } - std::string msg = llformat("%s %d, %d (%d x %d)", - tooltip_view->getName().c_str(), - left, - top, - rect.getWidth(), - rect.getHeight() ); - tooltip_msg->append( msg ); + LLRect rect = tooltip_view->getRect(); + LLRect parent_rect = tooltip_view->getParent()->getRect(); + S32 left = rect.mLeft; + // invert coordinate system for XUI top-left layout + S32 top = parent_rect.getHeight() - rect.mTop; + if (!tooltip_msg->empty()) + { + tooltip_msg->append("\n"); + } + std::string msg = llformat("%s %d, %d (%d x %d)", + tooltip_view->getName().c_str(), + left, + top, + rect.getWidth(), + rect.getHeight() ); + tooltip_msg->append( msg ); } BOOL LLPreviewedFloater::handleToolTip(S32 x, S32 y, MASK mask) { - if (!sShowRectangles) - { - return LLFloater::handleToolTip(x, y, mask); - } - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - std::string tooltip_msg; - LLView* tooltip_view = this; - LLView::tree_iterator_t end_it = endTreeDFS(); - for (LLView::tree_iterator_t it = beginTreeDFS(); it != end_it; ++it) - { - LLView* viewp = *it; - LLRect screen_rect; - viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect); - if (!(viewp->getVisible() - && screen_rect.pointInRect(screen_x, screen_y))) - { - it.skipDescendants(); - } - // only report xui names for LLUICtrls, not the various container LLViews - - else if (dynamic_cast(viewp)) - { - // if we are in a new part of the tree (not a descendent of current tooltip_view) - // then push the results for tooltip_view and start with a new potential view - // NOTE: this emulates visiting only the leaf nodes that meet our criteria - - if (tooltip_view != this - && !viewp->hasAncestor(tooltip_view)) - { - append_view_tooltip(tooltip_view, &tooltip_msg); - } - tooltip_view = viewp; - } - } - - append_view_tooltip(tooltip_view, &tooltip_msg); - - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tooltip_msg) - .max_width(400)); - return TRUE; + if (!sShowRectangles) + { + return LLFloater::handleToolTip(x, y, mask); + } + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + std::string tooltip_msg; + LLView* tooltip_view = this; + LLView::tree_iterator_t end_it = endTreeDFS(); + for (LLView::tree_iterator_t it = beginTreeDFS(); it != end_it; ++it) + { + LLView* viewp = *it; + LLRect screen_rect; + viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect); + if (!(viewp->getVisible() + && screen_rect.pointInRect(screen_x, screen_y))) + { + it.skipDescendants(); + } + // only report xui names for LLUICtrls, not the various container LLViews + + else if (dynamic_cast(viewp)) + { + // if we are in a new part of the tree (not a descendent of current tooltip_view) + // then push the results for tooltip_view and start with a new potential view + // NOTE: this emulates visiting only the leaf nodes that meet our criteria + + if (tooltip_view != this + && !viewp->hasAncestor(tooltip_view)) + { + append_view_tooltip(tooltip_view, &tooltip_msg); + } + tooltip_view = viewp; + } + } + + append_view_tooltip(tooltip_view, &tooltip_msg); + + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(tooltip_msg) + .max_width(400)); + return TRUE; } BOOL LLPreviewedFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) { - selectElement(this,x,y,0); - return TRUE; + selectElement(this,x,y,0); + return TRUE; } // *NOTE: In order to hide all of the overlapping elements of the selected element so as to see it in context, here is what you would need to do: @@ -1433,131 +1433,131 @@ BOOL LLPreviewedFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) // ~Jacob, 8/08 BOOL LLPreviewedFloater::selectElement(LLView* parent, int x, int y, int depth) { - if(getVisible()) - { - BOOL handled = FALSE; - if(LLFloaterUIPreview::containerType(parent)) - { - for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) - { - LLView* child = *child_it; - S32 local_x = x - child->getRect().mLeft; - S32 local_y = y - child->getRect().mBottom; - if (child->pointInView(local_x, local_y) && - child->getVisible() && - selectElement(child, x, y, ++depth)) - { - handled = TRUE; - break; - } - } - } - - if(!handled) - { - LLView::sPreviewClickedElement = parent; - } - return TRUE; - } - else - { - return FALSE; - } + if(getVisible()) + { + BOOL handled = FALSE; + if(LLFloaterUIPreview::containerType(parent)) + { + for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) + { + LLView* child = *child_it; + S32 local_x = x - child->getRect().mLeft; + S32 local_y = y - child->getRect().mBottom; + if (child->pointInView(local_x, local_y) && + child->getVisible() && + selectElement(child, x, y, ++depth)) + { + handled = TRUE; + break; + } + } + } + + if(!handled) + { + LLView::sPreviewClickedElement = parent; + } + return TRUE; + } + else + { + return FALSE; + } } void LLPreviewedFloater::draw() { - if(NULL != mFloaterUIPreview) - { - // Set and unset sDrawPreviewHighlights flag so as to avoid using two flags - if(mFloaterUIPreview->mHighlightingOverlaps) - { - LLView::sDrawPreviewHighlights = TRUE; - } - - // If we're looking for truncations, draw debug rects for the displayed - // floater only. - bool old_debug_rects = LLView::sDebugRects; - bool old_show_names = LLView::sDebugRectsShowNames; - if (sShowRectangles) - { - LLView::sDebugRects = true; - LLView::sDebugRectsShowNames = false; - } - - LLFloater::draw(); - - LLView::sDebugRects = old_debug_rects; - LLView::sDebugRectsShowNames = old_show_names; - - if(mFloaterUIPreview->mHighlightingOverlaps) - { - LLView::sDrawPreviewHighlights = FALSE; - } - } + if(NULL != mFloaterUIPreview) + { + // Set and unset sDrawPreviewHighlights flag so as to avoid using two flags + if(mFloaterUIPreview->mHighlightingOverlaps) + { + LLView::sDrawPreviewHighlights = TRUE; + } + + // If we're looking for truncations, draw debug rects for the displayed + // floater only. + bool old_debug_rects = LLView::sDebugRects; + bool old_show_names = LLView::sDebugRectsShowNames; + if (sShowRectangles) + { + LLView::sDebugRects = true; + LLView::sDebugRectsShowNames = false; + } + + LLFloater::draw(); + + LLView::sDebugRects = old_debug_rects; + LLView::sDebugRectsShowNames = old_show_names; + + if(mFloaterUIPreview->mHighlightingOverlaps) + { + LLView::sDrawPreviewHighlights = FALSE; + } + } } void LLFloaterUIPreview::onClickToggleOverlapping() { - if(LLView::sHighlightingDiffs) - { - onClickToggleDiffHighlighting(); - mToggleHighlightButton->toggleState(); - } - LLView::sPreviewHighlightedElements.clear(); // clear lists first - - S32 width, height; - getResizeLimits(&width, &height); // illegal call of non-static member function - if(mHighlightingOverlaps) - { - mHighlightingOverlaps = !mHighlightingOverlaps; - // reset list of preview highlighted elements - setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight - mOverlapPanel->getRect().getWidth(),getRect().mBottom)); - setResizeLimits(width - mOverlapPanel->getRect().getWidth(), height); - } - else - { - mHighlightingOverlaps = !mHighlightingOverlaps; - displayFloater(FALSE,1); - setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight + mOverlapPanel->getRect().getWidth(),getRect().mBottom)); - setResizeLimits(width + mOverlapPanel->getRect().getWidth(), height); - } - getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); + if(LLView::sHighlightingDiffs) + { + onClickToggleDiffHighlighting(); + mToggleHighlightButton->toggleState(); + } + LLView::sPreviewHighlightedElements.clear(); // clear lists first + + S32 width, height; + getResizeLimits(&width, &height); // illegal call of non-static member function + if(mHighlightingOverlaps) + { + mHighlightingOverlaps = !mHighlightingOverlaps; + // reset list of preview highlighted elements + setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight - mOverlapPanel->getRect().getWidth(),getRect().mBottom)); + setResizeLimits(width - mOverlapPanel->getRect().getWidth(), height); + } + else + { + mHighlightingOverlaps = !mHighlightingOverlaps; + displayFloater(FALSE,1); + setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight + mOverlapPanel->getRect().getWidth(),getRect().mBottom)); + setResizeLimits(width + mOverlapPanel->getRect().getWidth(), height); + } + getChildView("overlap_scroll")->setVisible( mHighlightingOverlaps); } void LLFloaterUIPreview::findOverlapsInChildren(LLView* parent) { - if(parent->getChildCount() == 0 || !containerType(parent)) // if it has no children or isn't a container type, skip it - { - return; - } - - // for every child of the parent - for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) - { - LLView* child = *child_it; - if(overlapIgnorable(child)) - { - continue; - } - - // for every sibling - for(child_list_const_iter_t sibling_it = parent->getChildList()->begin(); sibling_it != parent->getChildList()->end(); ++sibling_it) // for each sibling - { - LLView* sibling = *sibling_it; - if(overlapIgnorable(sibling)) - { - continue; - } - - // if they overlap... (we don't care if they're visible or enabled -- we want to check those anyway, i.e. hidden tabs that can be later shown) - if(sibling != child && elementOverlap(child, sibling)) - { - mOverlapPanel->mOverlapMap[child].push_back(sibling); // add to the map - } - } - findOverlapsInChildren(child); // recur - } + if(parent->getChildCount() == 0 || !containerType(parent)) // if it has no children or isn't a container type, skip it + { + return; + } + + // for every child of the parent + for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) + { + LLView* child = *child_it; + if(overlapIgnorable(child)) + { + continue; + } + + // for every sibling + for(child_list_const_iter_t sibling_it = parent->getChildList()->begin(); sibling_it != parent->getChildList()->end(); ++sibling_it) // for each sibling + { + LLView* sibling = *sibling_it; + if(overlapIgnorable(sibling)) + { + continue; + } + + // if they overlap... (we don't care if they're visible or enabled -- we want to check those anyway, i.e. hidden tabs that can be later shown) + if(sibling != child && elementOverlap(child, sibling)) + { + mOverlapPanel->mOverlapMap[child].push_back(sibling); // add to the map + } + } + findOverlapsInChildren(child); // recur + } } // *HACK: don't overlap with the drag handle and various other elements @@ -1565,153 +1565,153 @@ void LLFloaterUIPreview::findOverlapsInChildren(LLView* parent) // *NOTE: If a list of elements which have localizable content were created, this function should return false if viewp's class is in that list. BOOL LLFloaterUIPreview::overlapIgnorable(LLView* viewp) { - return NULL != dynamic_cast(viewp) || - NULL != dynamic_cast(viewp) || - NULL != dynamic_cast(viewp); + return NULL != dynamic_cast(viewp) || + NULL != dynamic_cast(viewp) || + NULL != dynamic_cast(viewp); } // *HACK: these are the only two container types as of 8/08, per Richard // This is using dynamic casts because there is no object-oriented way to tell which elements are containers. BOOL LLFloaterUIPreview::containerType(LLView* viewp) { - return NULL != dynamic_cast(viewp) || NULL != dynamic_cast(viewp); + return NULL != dynamic_cast(viewp) || NULL != dynamic_cast(viewp); } // Check if two llview's rectangles overlap, with some tolerance BOOL LLFloaterUIPreview::elementOverlap(LLView* view1, LLView* view2) { - LLSD rec1 = view1->getRect().getValue(); - LLSD rec2 = view2->getRect().getValue(); - int tolerance = 2; - return (int)rec1[0] <= (int)rec2[2] - tolerance && - (int)rec2[0] <= (int)rec1[2] - tolerance && - (int)rec1[3] <= (int)rec2[1] - tolerance && - (int)rec2[3] <= (int)rec1[1] - tolerance; + LLSD rec1 = view1->getRect().getValue(); + LLSD rec2 = view2->getRect().getValue(); + int tolerance = 2; + return (int)rec1[0] <= (int)rec2[2] - tolerance && + (int)rec2[0] <= (int)rec1[2] - tolerance && + (int)rec1[3] <= (int)rec2[1] - tolerance && + (int)rec2[3] <= (int)rec1[1] - tolerance; } void LLOverlapPanel::draw() { - static const std::string current_selection_text("Current selection: "); - static const std::string overlapper_text("Overlapper: "); - LLColor4 text_color = LLColor4::grey; - gGL.color4fv(text_color.mV); - - if(!LLView::sPreviewClickedElement) - { - LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 - LLView::sDrawPreviewHighlights = FALSE; - LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - } - else - { - OverlapMap::iterator iterExists = mOverlapMap.find(LLView::sPreviewClickedElement); - if(iterExists == mOverlapMap.end()) - { - return; - } - - std::list overlappers = mOverlapMap[LLView::sPreviewClickedElement]; - if(overlappers.size() == 0) - { - LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 - LLView::sDrawPreviewHighlights = FALSE; - std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)"); - S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10; - LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - // widen panel enough to fit this text - LLRect rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); - return; - } - - // recalculate required with and height; otherwise use cached - BOOL need_to_recalculate_bounds = FALSE; - if(mLastClickedElement == NULL) - { - need_to_recalculate_bounds = TRUE; - } - - if(NULL == mLastClickedElement) - { - mLastClickedElement = LLView::sPreviewClickedElement; - } - - // recalculate bounds for scroll panel - if(need_to_recalculate_bounds || LLView::sPreviewClickedElement->getName() != mLastClickedElement->getName()) - { - // reset panel's rectangle to its default width and height (300x600) - LLRect panel_rect = getRect(); - setRect(LLRect(panel_rect.mLeft,panel_rect.mTop,panel_rect.mLeft+getRect().getWidth(),panel_rect.mTop-getRect().getHeight())); - - LLRect rect; - - // change bounds for selected element - int height_sum = mLastClickedElement->getRect().getHeight() + mSpacing + 80; - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > mLastClickedElement->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + mLastClickedElement->getRect().getWidth() + 5, rect.mBottom)); - - // and widen to accomodate text if that's wider - std::string display_text = current_selection_text + LLView::sPreviewClickedElement->getName(); - S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); - - std::list overlappers = mOverlapMap[LLView::sPreviewClickedElement]; - for(std::list::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) - { - LLView* viewp = *overlap_it; - height_sum += viewp->getRect().getHeight() + mSpacing*3; - - // widen panel's rectangle to accommodate widest overlapping element of this floater - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > viewp->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + viewp->getRect().getWidth() + 5, rect.mBottom)); - - // and widen to accomodate text if that's wider - std::string display_text = overlapper_text + viewp->getName(); - S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); - } - // change panel's height to accommodate all element heights plus spacing between them - rect = getRect(); - setRect(LLRect(rect.mLeft,rect.mTop,rect.mRight,rect.mTop-height_sum)); - } - - LLUI::translate(5,getRect().getHeight()-10); // translate to top left - LLView::sDrawPreviewHighlights = FALSE; - - // draw currently-selected element at top of overlappers - LLUI::translate(0,-mSpacing); - LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height - LLView::sPreviewClickedElement->draw(); - - for(std::list::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) - { - LLView* viewp = *overlap_it; - - // draw separating line - LLUI::translate(0,-mSpacing); - gl_line_2d(0,0,getRect().getWidth()-10,0,LLColor4(192.0f/255.0f,192.0f/255.0f,192.0f/255.0f)); - - // draw name - LLUI::translate(0,-mSpacing); - LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - - // draw element - LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height - viewp->draw(); - } - mLastClickedElement = LLView::sPreviewClickedElement; - } + static const std::string current_selection_text("Current selection: "); + static const std::string overlapper_text("Overlapper: "); + LLColor4 text_color = LLColor4::grey; + gGL.color4fv(text_color.mV); + + if(!LLView::sPreviewClickedElement) + { + LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 + LLView::sDrawPreviewHighlights = FALSE; + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + } + else + { + OverlapMap::iterator iterExists = mOverlapMap.find(LLView::sPreviewClickedElement); + if(iterExists == mOverlapMap.end()) + { + return; + } + + std::list overlappers = mOverlapMap[LLView::sPreviewClickedElement]; + if(overlappers.size() == 0) + { + LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 + LLView::sDrawPreviewHighlights = FALSE; + std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)"); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10; + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + // widen panel enough to fit this text + LLRect rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + return; + } + + // recalculate required with and height; otherwise use cached + BOOL need_to_recalculate_bounds = FALSE; + if(mLastClickedElement == NULL) + { + need_to_recalculate_bounds = TRUE; + } + + if(NULL == mLastClickedElement) + { + mLastClickedElement = LLView::sPreviewClickedElement; + } + + // recalculate bounds for scroll panel + if(need_to_recalculate_bounds || LLView::sPreviewClickedElement->getName() != mLastClickedElement->getName()) + { + // reset panel's rectangle to its default width and height (300x600) + LLRect panel_rect = getRect(); + setRect(LLRect(panel_rect.mLeft,panel_rect.mTop,panel_rect.mLeft+getRect().getWidth(),panel_rect.mTop-getRect().getHeight())); + + LLRect rect; + + // change bounds for selected element + int height_sum = mLastClickedElement->getRect().getHeight() + mSpacing + 80; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > mLastClickedElement->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + mLastClickedElement->getRect().getWidth() + 5, rect.mBottom)); + + // and widen to accomodate text if that's wider + std::string display_text = current_selection_text + LLView::sPreviewClickedElement->getName(); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + + std::list overlappers = mOverlapMap[LLView::sPreviewClickedElement]; + for(std::list::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) + { + LLView* viewp = *overlap_it; + height_sum += viewp->getRect().getHeight() + mSpacing*3; + + // widen panel's rectangle to accommodate widest overlapping element of this floater + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > viewp->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + viewp->getRect().getWidth() + 5, rect.mBottom)); + + // and widen to accomodate text if that's wider + std::string display_text = overlapper_text + viewp->getName(); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + } + // change panel's height to accommodate all element heights plus spacing between them + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.mRight,rect.mTop-height_sum)); + } + + LLUI::translate(5,getRect().getHeight()-10); // translate to top left + LLView::sDrawPreviewHighlights = FALSE; + + // draw currently-selected element at top of overlappers + LLUI::translate(0,-mSpacing); + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height + LLView::sPreviewClickedElement->draw(); + + for(std::list::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) + { + LLView* viewp = *overlap_it; + + // draw separating line + LLUI::translate(0,-mSpacing); + gl_line_2d(0,0,getRect().getWidth()-10,0,LLColor4(192.0f/255.0f,192.0f/255.0f,192.0f/255.0f)); + + // draw name + LLUI::translate(0,-mSpacing); + LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + + // draw element + LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height + viewp->draw(); + } + mLastClickedElement = LLView::sPreviewClickedElement; + } } void LLFloaterUIPreviewUtil::registerFloater() { - LLFloaterReg::add("ui_preview", "floater_ui_preview.xml", - &LLFloaterReg::build); + LLFloaterReg::add("ui_preview", "floater_ui_preview.xml", + &LLFloaterReg::build); } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0144f13f24..df543ecbc7 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -28,7 +28,7 @@ #include "llimview.h" -#include "llavatarnamecache.h" // IDEVO +#include "llavatarnamecache.h" // IDEVO #include "llavataractions.h" #include "llfloaterconversationlog.h" #include "llfloaterreg.h" @@ -101,14 +101,14 @@ LLIMMgr* gIMMgr = NULL; bool LLSessionTimeoutTimer::tick() { - if (mSessionId.isNull()) return true; + if (mSessionId.isNull()) return true; - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); - if (session && !session->mSessionInitialized) - { - gIMMgr->showSessionStartError("session_initialization_timed_out_error", mSessionId); - } - return true; + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); + if (session && !session->mSessionInitialized) + { + gIMMgr->showSessionStartError("session_initialization_timed_out_error", mSessionId); + } + return true; } @@ -146,25 +146,25 @@ void process_dnd_im(const LLSD& notification) static void on_avatar_name_cache_toast(const LLUUID& agent_id, - const LLAvatarName& av_name, - LLSD msg) + const LLAvatarName& av_name, + LLSD msg) { - LLSD args; - args["MESSAGE"] = msg["message"]; - args["TIME"] = msg["time"]; - // *TODO: Can this ever be an object name or group name? - args["FROM"] = av_name.getCompleteName(); - args["FROM_ID"] = msg["from_id"]; - args["SESSION_ID"] = msg["session_id"]; - args["SESSION_TYPE"] = msg["session_type"]; - LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); + LLSD args; + args["MESSAGE"] = msg["message"]; + args["TIME"] = msg["time"]; + // *TODO: Can this ever be an object name or group name? + args["FROM"] = av_name.getCompleteName(); + args["FROM_ID"] = msg["from_id"]; + args["SESSION_ID"] = msg["session_id"]; + args["SESSION_TYPE"] = msg["session_type"]; + LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); } void notify_of_message(const LLSD& msg, bool is_dnd_msg) { 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(); + 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); // do not show notification which goes from agent @@ -178,222 +178,222 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance("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(); - if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) - { - conversations_floater_status = CLOSED; - } - else if (!im_box->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; - } + 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(); + if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) + { + conversations_floater_status = CLOSED; + } + else if (!im_box->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()) { - if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT) - { - user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundObjectIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } - } - else - { - user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } - } - } + if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT) + { + user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundObjectIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else + { + 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"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } + user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } } else { - user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); + 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"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); + 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"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } + user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } } // actions: // 0. nothing - exit if (("noaction" == user_preferences || - ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) - && session_floater->isMessagePaneExpanded()) + ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) + && session_floater->isMessagePaneExpanded()) { - return; + return; } // 1. open floater and [optional] surface it if ("openconversations" == user_preferences && - (CLOSED == conversations_floater_status - || NOT_ON_TOP == conversations_floater_status)) + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) { - if(!gAgent.isDoNotDisturb()) + if(!gAgent.isDoNotDisturb()) { - if(!LLAppViewer::instance()->quitRequested() && !LLFloater::isVisible(im_box)) - { - // Open conversations floater - LLFloaterReg::showInstance("im_container"); - } - im_box->collapseMessagesPane(false); - if (session_floater) - { - if (session_floater->getHost()) - { - if (NULL != im_box && im_box->isMinimized()) - { - LLFloater::onClickMinimize(im_box); - } - } - else - { - if (session_floater->isMinimized()) - { - LLFloater::onClickMinimize(session_floater); - } - } - } - } + if(!LLAppViewer::instance()->quitRequested() && !LLFloater::isVisible(im_box)) + { + // Open conversations floater + LLFloaterReg::showInstance("im_container"); + } + im_box->collapseMessagesPane(false); + if (session_floater) + { + if (session_floater->getHost()) + { + if (NULL != im_box && im_box->isMinimized()) + { + LLFloater::onClickMinimize(im_box); + } + } + else + { + if (session_floater->isMinimized()) + { + LLFloater::onClickMinimize(session_floater); + } + } + } + } else { - store_dnd_message = true; - } + 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) - || ("flash" == user_preferences && (CLOSED == conversations_floater_status - || NOT_ON_TOP == conversations_floater_status)) - || is_dnd_msg) - { - if(!LLMuteList::getInstance()->isMuted(participant_id)) - { - if(gAgent.isDoNotDisturb()) - { - store_dnd_message = true; - } - else - { - if (is_dnd_msg && (ON_TOP == conversations_floater_status || - NOT_ON_TOP == conversations_floater_status || - CLOSED == conversations_floater_status)) - { - im_box->highlightConversationItemWidget(session_id, true); - } - else - { - im_box->flashConversationItemWidget(session_id, true); - } - } - } - } + || 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(gAgent.isDoNotDisturb()) + { + store_dnd_message = true; + } + else + { + if (is_dnd_msg && (ON_TOP == conversations_floater_status || + NOT_ON_TOP == conversations_floater_status || + CLOSED == conversations_floater_status)) + { + im_box->highlightConversationItemWidget(session_id, true); + } + else + { + im_box->flashConversationItemWidget(session_id, true); + } + } + } + } // 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; - } - } - } + (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) && - (ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) && - (!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) - || !session_floater->isMessagePaneExpanded()) + (ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) && + (!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) + || !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()) { - if(!is_dnd_msg) - { - if(gAgent.isDoNotDisturb()) - { - store_dnd_message = true; - } - else - { + if(!is_dnd_msg) + { + if(gAgent.isDoNotDisturb()) + { + store_dnd_message = true; + } + else + { LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); } } } - } - if (store_dnd_message) - { - // If in DND mode, allow notification to be stored so upon DND exit - // the user will be notified with some limitations (see 'is_dnd_msg' flag checks) - if(session_id.notNull() - && participant_id.notNull() - && !session_floater->isShown()) - { - LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); - } - } + } + if (store_dnd_message) + { + // If in DND mode, allow notification to be stored so upon DND exit + // the user will be notified with some limitations (see 'is_dnd_msg' flag checks) + if(session_id.notNull() + && participant_id.notNull() + && !session_floater->isShown()) + { + LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); + } + } } void on_new_message(const LLSD& msg) { - notify_of_message(msg, false); + notify_of_message(msg, false); } void startConfrenceCoro(std::string url, @@ -638,251 +638,251 @@ void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from, LLIMModel::LLIMModel() { - addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); - addNewMsgCallback(boost::bind(&on_new_message, _1)); - LLCallDialogManager::instance(); + addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); + addNewMsgCallback(boost::bind(&on_new_message, _1)); + LLCallDialogManager::instance(); } LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) -: mSessionID(session_id), - mName(name), - mType(type), - mHasOfflineMessage(has_offline_msg), - mParticipantUnreadMessageCount(0), - mNumUnread(0), - mOtherParticipantID(other_participant_id), - mInitialTargetIDs(ids), - mVoiceChannel(NULL), - mSpeakers(NULL), - mSessionInitialized(false), - mCallBackEnabled(true), - mTextIMPossible(true), - mStartCallOnInitialize(false), - mStartedAsIMCall(voice), - mIsDNDsend(false), - mAvatarNameCacheConnection() -{ - // set P2P type by default - mSessionType = P2P_SESSION; - - if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) - { - mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); - } - else - { - mVoiceChannel = new LLVoiceChannelGroup(session_id, name); - - // determine whether it is group or conference session - if (gAgent.isInGroup(mSessionID)) - { - mSessionType = GROUP_SESSION; - } - else - { - mSessionType = ADHOC_SESSION; - } - } - - if(mVoiceChannel) - { - mVoiceChannelStateChangeConnection = mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2, _3)); - } - - mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); - - // All participants will be added to the list of people we've recently interacted with. - - // we need to add only _active_ speakers...so comment this. - // may delete this later on cleanup - //mSpeakers->addListener(&LLRecentPeople::instance(), "add"); - - //we need to wait for session initialization for outgoing ad-hoc and group chat session - //correct session id for initiated ad-hoc chat will be received from the server - if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, - mInitialTargetIDs, mType)) - { - //we don't need to wait for any responses - //so we're already initialized - mSessionInitialized = true; - } - else - { - //tick returns TRUE - timer will be deleted after the tick - new LLSessionTimeoutTimer(mSessionID, SESSION_INITIALIZATION_TIMEOUT); - } - - if (IM_NOTHING_SPECIAL == mType) - { - mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); - mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); - } - - buildHistoryFileName(); - loadHistory(); - - // Localizing name of ad-hoc session. STORM-153 - // Changing name should happen here- after the history file was created, so that - // history files have consistent (English) names in different locales. - if (isAdHocSessionType() && IM_SESSION_INVITE == mType) - { - mAvatarNameCacheConnection = LLAvatarNameCache::get(mOtherParticipantID,boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,this, _2)); - } +: mSessionID(session_id), + mName(name), + mType(type), + mHasOfflineMessage(has_offline_msg), + mParticipantUnreadMessageCount(0), + mNumUnread(0), + mOtherParticipantID(other_participant_id), + mInitialTargetIDs(ids), + mVoiceChannel(NULL), + mSpeakers(NULL), + mSessionInitialized(false), + mCallBackEnabled(true), + mTextIMPossible(true), + mStartCallOnInitialize(false), + mStartedAsIMCall(voice), + mIsDNDsend(false), + mAvatarNameCacheConnection() +{ + // set P2P type by default + mSessionType = P2P_SESSION; + + if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) + { + mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); + } + else + { + mVoiceChannel = new LLVoiceChannelGroup(session_id, name); + + // determine whether it is group or conference session + if (gAgent.isInGroup(mSessionID)) + { + mSessionType = GROUP_SESSION; + } + else + { + mSessionType = ADHOC_SESSION; + } + } + + if(mVoiceChannel) + { + mVoiceChannelStateChangeConnection = mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2, _3)); + } + + mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); + + // All participants will be added to the list of people we've recently interacted with. + + // we need to add only _active_ speakers...so comment this. + // may delete this later on cleanup + //mSpeakers->addListener(&LLRecentPeople::instance(), "add"); + + //we need to wait for session initialization for outgoing ad-hoc and group chat session + //correct session id for initiated ad-hoc chat will be received from the server + if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, + mInitialTargetIDs, mType)) + { + //we don't need to wait for any responses + //so we're already initialized + mSessionInitialized = true; + } + else + { + //tick returns TRUE - timer will be deleted after the tick + new LLSessionTimeoutTimer(mSessionID, SESSION_INITIALIZATION_TIMEOUT); + } + + if (IM_NOTHING_SPECIAL == mType) + { + mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); + mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); + } + + buildHistoryFileName(); + loadHistory(); + + // Localizing name of ad-hoc session. STORM-153 + // Changing name should happen here- after the history file was created, so that + // history files have consistent (English) names in different locales. + if (isAdHocSessionType() && IM_SESSION_INVITE == mType) + { + mAvatarNameCacheConnection = LLAvatarNameCache::get(mOtherParticipantID,boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,this, _2)); + } } void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name) { - mAvatarNameCacheConnection.disconnect(); - - if (!av_name.isValidName()) - { - S32 separator_index = mName.rfind(" "); - std::string name = mName.substr(0, separator_index); - ++separator_index; - std::string conference_word = mName.substr(separator_index, mName.length()); - - // additional check that session name is what we expected - if ("Conference" == conference_word) - { - LLStringUtil::format_map_t args; - args["[AGENT_NAME]"] = name; - LLTrans::findString(mName, "conference-title-incoming", args); - } - } - else - { - LLStringUtil::format_map_t args; - args["[AGENT_NAME]"] = av_name.getCompleteName(); - LLTrans::findString(mName, "conference-title-incoming", args); - } + mAvatarNameCacheConnection.disconnect(); + + if (!av_name.isValidName()) + { + S32 separator_index = mName.rfind(" "); + std::string name = mName.substr(0, separator_index); + ++separator_index; + std::string conference_word = mName.substr(separator_index, mName.length()); + + // additional check that session name is what we expected + if ("Conference" == conference_word) + { + LLStringUtil::format_map_t args; + args["[AGENT_NAME]"] = name; + LLTrans::findString(mName, "conference-title-incoming", args); + } + } + else + { + LLStringUtil::format_map_t args; + args["[AGENT_NAME]"] = av_name.getCompleteName(); + LLTrans::findString(mName, "conference-title-incoming", args); + } } void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction) { - std::string you_joined_call = LLTrans::getString("you_joined_call"); - std::string you_started_call = LLTrans::getString("you_started_call"); - std::string other_avatar_name = ""; - LLAvatarName av_name; - - std::string message; - - switch(mSessionType) - { - case P2P_SESSION: - LLAvatarNameCache::get(mOtherParticipantID, &av_name); - other_avatar_name = av_name.getUserName(); - - if(direction == LLVoiceChannel::INCOMING_CALL) - { - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - { - LLStringUtil::format_map_t string_args; - string_args["[NAME]"] = other_avatar_name; - message = LLTrans::getString("name_started_call", string_args); - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); - break; - } - case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); - default: - break; - } - } - else // outgoing call - { - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); - break; - case LLVoiceChannel::STATE_CONNECTED : - message = LLTrans::getString("answered_call"); - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); - default: - break; - } - } - break; - - case GROUP_SESSION: - case ADHOC_SESSION: - if(direction == LLVoiceChannel::INCOMING_CALL) - { - switch(new_state) - { - case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); - default: - break; - } - } - else // outgoing call - { - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); - break; - default: - break; - } - } - default: - break; - } - // Update speakers list when connected - if (LLVoiceChannel::STATE_CONNECTED == new_state) - { - mSpeakers->update(true); - } + std::string you_joined_call = LLTrans::getString("you_joined_call"); + std::string you_started_call = LLTrans::getString("you_started_call"); + std::string other_avatar_name = ""; + LLAvatarName av_name; + + std::string message; + + switch(mSessionType) + { + case P2P_SESSION: + LLAvatarNameCache::get(mOtherParticipantID, &av_name); + other_avatar_name = av_name.getUserName(); + + if(direction == LLVoiceChannel::INCOMING_CALL) + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + { + LLStringUtil::format_map_t string_args; + string_args["[NAME]"] = other_avatar_name; + message = LLTrans::getString("name_started_call", string_args); + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); + break; + } + case LLVoiceChannel::STATE_CONNECTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); + default: + break; + } + } + else // outgoing call + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); + break; + case LLVoiceChannel::STATE_CONNECTED : + message = LLTrans::getString("answered_call"); + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message); + default: + break; + } + } + break; + + case GROUP_SESSION: + case ADHOC_SESSION: + if(direction == LLVoiceChannel::INCOMING_CALL) + { + switch(new_state) + { + case LLVoiceChannel::STATE_CONNECTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call); + default: + break; + } + } + else // outgoing call + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call); + break; + default: + break; + } + } + default: + break; + } + // Update speakers list when connected + if (LLVoiceChannel::STATE_CONNECTED == new_state) + { + mSpeakers->update(true); + } } LLIMModel::LLIMSession::~LLIMSession() { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - - delete mSpeakers; - mSpeakers = NULL; + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } - // End the text IM session if necessary - if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull()) - { - switch(mType) - { - case IM_NOTHING_SPECIAL: - case IM_SESSION_P2P_INVITE: - LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID); - break; + delete mSpeakers; + mSpeakers = NULL; - default: - // Appease the linux compiler - break; - } - } + // End the text IM session if necessary + if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull()) + { + switch(mType) + { + case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: + LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID); + break; + + default: + // Appease the linux compiler + break; + } + } - mVoiceChannelStateChangeConnection.disconnect(); + mVoiceChannelStateChangeConnection.disconnect(); - // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). - mVoiceChannel->deactivate(); + // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). + mVoiceChannel->deactivate(); - delete mVoiceChannel; - mVoiceChannel = NULL; + delete mVoiceChannel; + mVoiceChannel = NULL; } void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id) { - mSessionInitialized = true; + mSessionInitialized = true; - if (new_session_id != mSessionID) - { - mSessionID = new_session_id; - mVoiceChannel->updateSessionID(new_session_id); - } + if (new_session_id != mSessionID) + { + mSessionID = new_session_id; + mVoiceChannel->updateSessionID(new_session_id); + } } void LLIMModel::LLIMSession::addMessage(const std::string& from, @@ -893,40 +893,40 @@ void LLIMModel::LLIMSession::addMessage(const std::string& from, const bool is_region_msg, const U32 timestamp) // may be zero { - LLSD message; - message["from"] = from; - message["from_id"] = from_id; - message["message"] = utf8_text; - message["time"] = time; // string used in display, may be full data YYYY/MM/DD HH:MM or just HH:MM + LLSD message; + message["from"] = from; + message["from_id"] = from_id; + message["message"] = utf8_text; + message["time"] = time; // string used in display, may be full data YYYY/MM/DD HH:MM or just HH:MM message["timestamp"] = (S32)timestamp; // use string? LLLogChat::timestamp2LogString(timestamp, true); - message["index"] = (LLSD::Integer)mMsgs.size(); - message["is_history"] = is_history; - message["is_region_msg"] = is_region_msg; - - LL_DEBUGS("UIUsage") << "addMessage " << " from " << from << " from_id " << from_id << " utf8_text " << utf8_text << " time " << time << " is_history " << is_history << " session mType " << mType << LL_ENDL; - if (from_id == gAgent.getID()) - { - if (mType == IM_SESSION_GROUP_START) - { - LLUIUsage::instance().logCommand("Chat.SendGroup"); - } - else if (mType == IM_NOTHING_SPECIAL) - { - LLUIUsage::instance().logCommand("Chat.SendIM"); - } - else - { - LLUIUsage::instance().logCommand("Chat.SendOther"); - } - } - - mMsgs.push_front(message); // Add most recent messages to the front of mMsgs - - if (mSpeakers && from_id.notNull()) - { - mSpeakers->speakerChatted(from_id); - mSpeakers->setSpeakerTyping(from_id, FALSE); - } + message["index"] = (LLSD::Integer)mMsgs.size(); + message["is_history"] = is_history; + message["is_region_msg"] = is_region_msg; + + LL_DEBUGS("UIUsage") << "addMessage " << " from " << from << " from_id " << from_id << " utf8_text " << utf8_text << " time " << time << " is_history " << is_history << " session mType " << mType << LL_ENDL; + if (from_id == gAgent.getID()) + { + if (mType == IM_SESSION_GROUP_START) + { + LLUIUsage::instance().logCommand("Chat.SendGroup"); + } + else if (mType == IM_NOTHING_SPECIAL) + { + LLUIUsage::instance().logCommand("Chat.SendIM"); + } + else + { + LLUIUsage::instance().logCommand("Chat.SendOther"); + } + } + + mMsgs.push_front(message); // Add most recent messages to the front of mMsgs + + if (mSpeakers && from_id.notNull()) + { + mSpeakers->speakerChatted(from_id); + mSpeakers->setSpeakerTyping(from_id, FALSE); + } } void LLIMModel::LLIMSession::addMessagesFromHistoryCache(const chat_message_list_t& history) @@ -1206,329 +1206,329 @@ void LLIMModel::LLIMSession::addMessagesFromServerHistory(const LLSD& history, void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata) { - if (!userdata) return; + if (!userdata) return; - LLIMSession* self = (LLIMSession*) userdata; + LLIMSession* self = (LLIMSession*) userdata; - if (type == LLLogChat::LOG_LINE) - { + if (type == LLLogChat::LOG_LINE) + { LL_DEBUGS("ChatHistory") << "chatFromLogFile() adding LOG_LINE message from " << msg << LL_ENDL; self->addMessage("", LLSD(), msg["message"].asString(), "", true, false, 0); // from history data, not region message, no timestamp - } - else if (type == LLLogChat::LOG_LLSD) - { + } + else if (type == LLLogChat::LOG_LLSD) + { LL_DEBUGS("ChatHistory") << "chatFromLogFile() adding LOG_LLSD message from " << msg << LL_ENDL; self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString(), true, false, 0); // from history data, not region message, no timestamp - } + } } void LLIMModel::LLIMSession::loadHistory() { - mMsgs.clear(); + mMsgs.clear(); mLastHistoryCacheMsgs.clear(); mLastHistoryCacheDateTime.clear(); - if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) - { + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) + { // read and parse chat history from local file chat_message_list_t chat_history; - LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); + LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); addMessagesFromHistoryCache(chat_history); } } LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const { - return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); + return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); } //*TODO consider switching to using std::set instead of std::list for holding LLUUIDs across the whole code LLIMModel::LLIMSession* LLIMModel::findAdHocIMSession(const uuid_vec_t& ids) { - S32 num = ids.size(); - if (!num) return NULL; + S32 num = ids.size(); + if (!num) return NULL; - if (mId2SessionMap.empty()) return NULL; + if (mId2SessionMap.empty()) return NULL; - std::map::const_iterator it = mId2SessionMap.begin(); - for (; it != mId2SessionMap.end(); ++it) - { - LLIMSession* session = (*it).second; + std::map::const_iterator it = mId2SessionMap.begin(); + for (; it != mId2SessionMap.end(); ++it) + { + LLIMSession* session = (*it).second; - if (!session->isAdHoc()) continue; - if (session->mInitialTargetIDs.size() != num) continue; + if (!session->isAdHoc()) continue; + if (session->mInitialTargetIDs.size() != num) continue; - std::list tmp_list(session->mInitialTargetIDs.begin(), session->mInitialTargetIDs.end()); + std::list tmp_list(session->mInitialTargetIDs.begin(), session->mInitialTargetIDs.end()); - uuid_vec_t::const_iterator iter = ids.begin(); - while (iter != ids.end()) - { - tmp_list.remove(*iter); - ++iter; + uuid_vec_t::const_iterator iter = ids.begin(); + while (iter != ids.end()) + { + tmp_list.remove(*iter); + ++iter; - if (tmp_list.empty()) - { - break; - } - } + if (tmp_list.empty()) + { + break; + } + } - if (tmp_list.empty() && iter == ids.end()) - { - return session; - } - } + if (tmp_list.empty() && iter == ids.end()) + { + return session; + } + } - return NULL; + return NULL; } bool LLIMModel::LLIMSession::isOutgoingAdHoc() const { - return IM_SESSION_CONFERENCE_START == mType; + return IM_SESSION_CONFERENCE_START == mType; } bool LLIMModel::LLIMSession::isAdHoc() { - return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID, TRUE)); + return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID, TRUE)); } bool LLIMModel::LLIMSession::isP2P() { - return IM_NOTHING_SPECIAL == mType; + return IM_NOTHING_SPECIAL == mType; } bool LLIMModel::LLIMSession::isGroupChat() { - return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE)); + return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE)); } LLUUID LLIMModel::LLIMSession::generateOutgoingAdHocHash() const { - LLUUID hash = LLUUID::null; + LLUUID hash = LLUUID::null; - if (mInitialTargetIDs.size()) - { - std::set sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); - hash = generateHash(sorted_uuids); - } + if (mInitialTargetIDs.size()) + { + std::set sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); + hash = generateHash(sorted_uuids); + } - return hash; + return hash; } void LLIMModel::LLIMSession::buildHistoryFileName() { - mHistoryFileName = mName; - - //ad-hoc requires sophisticated chat history saving schemes - if (isAdHoc()) - { - /* in case of outgoing ad-hoc sessions we need to make specilized names - * if this naming system is ever changed then the filtering definitions in - * lllogchat.cpp need to be change acordingly so that the filtering for the - * date stamp code introduced in STORM-102 will work properly and not add - * a date stamp to the Ad-hoc conferences. - */ - if (mInitialTargetIDs.size()) - { - std::set sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); - mHistoryFileName = mName + " hash" + generateHash(sorted_uuids).asString(); - } - else - { - //in case of incoming ad-hoc sessions - mHistoryFileName = mName + " " + LLLogChat::timestamp2LogString(0, true) + " " + mSessionID.asString().substr(0, 4); - } - } - else if (isP2P()) // look up username to use as the log name - { - LLAvatarName av_name; - // For outgoing sessions we already have a cached name - // so no need for a callback in LLAvatarNameCache::get() - if (LLAvatarNameCache::get(mOtherParticipantID, &av_name)) - { - mHistoryFileName = LLCacheName::buildUsername(av_name.getUserName()); - } - else - { - // Incoming P2P sessions include a name that we can use to build a history file name - mHistoryFileName = LLCacheName::buildUsername(mName); - } + mHistoryFileName = mName; + + //ad-hoc requires sophisticated chat history saving schemes + if (isAdHoc()) + { + /* in case of outgoing ad-hoc sessions we need to make specilized names + * if this naming system is ever changed then the filtering definitions in + * lllogchat.cpp need to be change acordingly so that the filtering for the + * date stamp code introduced in STORM-102 will work properly and not add + * a date stamp to the Ad-hoc conferences. + */ + if (mInitialTargetIDs.size()) + { + std::set sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); + mHistoryFileName = mName + " hash" + generateHash(sorted_uuids).asString(); + } + else + { + //in case of incoming ad-hoc sessions + mHistoryFileName = mName + " " + LLLogChat::timestamp2LogString(0, true) + " " + mSessionID.asString().substr(0, 4); + } + } + else if (isP2P()) // look up username to use as the log name + { + LLAvatarName av_name; + // For outgoing sessions we already have a cached name + // so no need for a callback in LLAvatarNameCache::get() + if (LLAvatarNameCache::get(mOtherParticipantID, &av_name)) + { + mHistoryFileName = LLCacheName::buildUsername(av_name.getUserName()); + } + else + { + // Incoming P2P sessions include a name that we can use to build a history file name + mHistoryFileName = LLCacheName::buildUsername(mName); + } // user's account name can change, but filenames and session names are account name based LLConversationLog::getInstance()->verifyFilename(mSessionID, mHistoryFileName, av_name.getCompleteName()); - } - else if (isGroupChat()) - { - mHistoryFileName = mName + GROUP_CHAT_SUFFIX; - } + } + else if (isGroupChat()) + { + mHistoryFileName = mName + GROUP_CHAT_SUFFIX; + } } //static LLUUID LLIMModel::LLIMSession::generateHash(const std::set& sorted_uuids) { - LLMD5 md5_uuid; + LLMD5 md5_uuid; - std::set::const_iterator it = sorted_uuids.begin(); - while (it != sorted_uuids.end()) - { - md5_uuid.update((unsigned char*)(*it).mData, 16); - it++; - } - md5_uuid.finalize(); + std::set::const_iterator it = sorted_uuids.begin(); + while (it != sorted_uuids.end()) + { + md5_uuid.update((unsigned char*)(*it).mData, 16); + it++; + } + md5_uuid.finalize(); - LLUUID participants_md5_hash; - md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData); - return participants_md5_hash; + LLUUID participants_md5_hash; + md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData); + return participants_md5_hash; } void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) { - LLIMSession* session = findIMSession(old_session_id); - if (session) - { - session->sessionInitReplyReceived(new_session_id); + LLIMSession* session = findIMSession(old_session_id); + if (session) + { + session->sessionInitReplyReceived(new_session_id); - if (old_session_id != new_session_id) - { - mId2SessionMap.erase(old_session_id); - mId2SessionMap[new_session_id] = session; - } + if (old_session_id != new_session_id) + { + mId2SessionMap.erase(old_session_id); + mId2SessionMap[new_session_id] = session; + } - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(old_session_id); - if (im_floater) - { - im_floater->sessionInitReplyReceived(new_session_id); - } + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(old_session_id); + if (im_floater) + { + im_floater->sessionInitReplyReceived(new_session_id); + } - if (old_session_id != new_session_id) - { - gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); - } + if (old_session_id != new_session_id) + { + gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); + } - // auto-start the call on session initialization? - if (session->mStartCallOnInitialize) - { - gIMMgr->startCall(new_session_id); - } - } + // auto-start the call on session initialization? + if (session->mStartCallOnInitialize) + { + gIMMgr->startCall(new_session_id); + } + } } void LLIMModel::testMessages() { - LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); - LLUUID bot1_session_id; - std::string from = "IM Tester"; + LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); + LLUUID bot1_session_id; + std::string from = "IM Tester"; - bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); - newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); - addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); + bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); + newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); + addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); - LLUUID bot2_id; - std::string firstname[] = {"Roflcopter", "Joe"}; - std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; + LLUUID bot2_id; + std::string firstname[] = {"Roflcopter", "Joe"}; + std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; - S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); - S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); + S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); + S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); - from = firstname[rand1] + " " + lastname[rand2]; - bot2_id.generate(from); - LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); - newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); - addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? "); - addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); + from = firstname[rand1] + " " + lastname[rand2]; + bot2_id.generate(from); + LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); + newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); + addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? "); + addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); } //session name should not be empty bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, - const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) + const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) { - if (name.empty()) - { - LL_WARNS() << "Attempt to create a new session with empty name; id = " << session_id << LL_ENDL; - return false; - } + if (name.empty()) + { + LL_WARNS() << "Attempt to create a new session with empty name; id = " << session_id << LL_ENDL; + return false; + } - if (findIMSession(session_id)) - { - LL_WARNS() << "IM Session " << session_id << " already exists" << LL_ENDL; - return false; - } + if (findIMSession(session_id)) + { + LL_WARNS() << "IM Session " << session_id << " already exists" << LL_ENDL; + return false; + } - LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); - mId2SessionMap[session_id] = session; + LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); + mId2SessionMap[session_id] = session; - // When notifying observer, name of session is used instead of "name", because they may not be the - // same if it is an adhoc session (in this case name is localized in LLIMSession constructor). - std::string session_name = LLIMModel::getInstance()->getName(session_id); - LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, session_name, other_participant_id,has_offline_msg); + // When notifying observer, name of session is used instead of "name", because they may not be the + // same if it is an adhoc session (in this case name is localized in LLIMSession constructor). + std::string session_name = LLIMModel::getInstance()->getName(session_id); + LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, session_name, other_participant_id,has_offline_msg); - return true; + return true; } bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, bool voice, bool has_offline_msg) { - uuid_vec_t ids; - ids.push_back(other_participant_id); - return newSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); + uuid_vec_t ids; + ids.push_back(other_participant_id); + return newSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); } bool LLIMModel::clearSession(const LLUUID& session_id) { - if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false; - delete (mId2SessionMap[session_id]); - mId2SessionMap.erase(session_id); - return true; + if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false; + delete (mId2SessionMap[session_id]); + mId2SessionMap.erase(session_id); + return true; } void LLIMModel::getMessages(const LLUUID& session_id, chat_message_list_t& messages, int start_index, const bool sendNoUnreadMsgs) { - getMessagesSilently(session_id, messages, start_index); + getMessagesSilently(session_id, messages, start_index); - if (sendNoUnreadMsgs) - { - sendNoUnreadMessages(session_id); - } + if (sendNoUnreadMsgs) + { + sendNoUnreadMessages(session_id); + } } void LLIMModel::getMessagesSilently(const LLUUID& session_id, chat_message_list_t& messages, int start_index) { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return; + } - int i = session->mMsgs.size() - start_index; + int i = session->mMsgs.size() - start_index; - for (chat_message_list_t::iterator iter = session->mMsgs.begin(); - iter != session->mMsgs.end() && i > 0; - iter++) - { - LLSD msg; - msg = *iter; - messages.push_back(*iter); - i--; - } + for (chat_message_list_t::iterator iter = session->mMsgs.begin(); + iter != session->mMsgs.end() && i > 0; + iter++) + { + LLSD msg; + msg = *iter; + messages.push_back(*iter); + i--; + } } void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id) { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return; + } - session->mNumUnread = 0; - session->mParticipantUnreadMessageCount = 0; + session->mNumUnread = 0; + session->mParticipantUnreadMessageCount = 0; - LLSD arg; - arg["session_id"] = session_id; - arg["num_unread"] = 0; - arg["participant_unread"] = session->mParticipantUnreadMessageCount; - mNoUnreadMsgsSignal(arg); + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = 0; + arg["participant_unread"] = session->mParticipantUnreadMessageCount; + mNoUnreadMsgsSignal(arg); } bool LLIMModel::addToHistory(const LLUUID& session_id, @@ -1538,54 +1538,54 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, bool is_region_msg, U32 timestamp) { - LLIMSession* session = findIMSession(session_id); + LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return false; - } + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return false; + } // This is where a normal arriving message is added to the session. Note that the time string created here is without the full date - session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp2LogString(timestamp, false), false, is_region_msg, timestamp); + session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp2LogString(timestamp, false), false, is_region_msg, timestamp); - return true; + return true; } bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { - if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1) - { - std::string from_name = from; + if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1) + { + std::string from_name = from; - LLAvatarName av_name; - if (!from_id.isNull() && - LLAvatarNameCache::get(from_id, &av_name) && - !av_name.isDisplayNameDefault()) - { - from_name = av_name.getCompleteName(); - } + LLAvatarName av_name; + if (!from_id.isNull() && + LLAvatarNameCache::get(from_id, &av_name) && + !av_name.isDisplayNameDefault()) + { + from_name = av_name.getCompleteName(); + } - LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text); - LLConversationLog::instance().cache(); // update the conversation log too - return true; - } - else - { - return false; - } + LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text); + LLConversationLog::instance().cache(); // update the conversation log too + return true; + } + else + { + return false; + } } void LLIMModel::proccessOnlineOfflineNotification( - const LLUUID& session_id, + const LLUUID& session_id, const std::string& utf8_text) { - // Add system message to history - addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); + // Add system message to history + addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); } void LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* = false */ U32 time_stamp /* = 0 */) + const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* = false */ U32 time_stamp /* = 0 */) { if (gSavedSettings.getBOOL("TranslateChat") && (from != SYSTEM_FROM)) { @@ -1631,442 +1631,442 @@ void LLIMModel::processAddingMessage(const LLUUID& session_id, const std::string } LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* false */ + const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* false */ U32 timestamp /* = 0 */) { - LLIMSession* session = findIMSession(session_id); + LLIMSession* session = findIMSession(session_id); - if (!session) - { - return NULL; - } + if (!session) + { + return NULL; + } - // replace interactive system message marker with correct from string value - std::string from_name = from; - if (INTERACTIVE_SYSTEM_FROM == from) - { - from_name = SYSTEM_FROM; - } + // replace interactive system message marker with correct from string value + std::string from_name = from; + if (INTERACTIVE_SYSTEM_FROM == from) + { + from_name = SYSTEM_FROM; + } - addToHistory(session_id, from_name, from_id, utf8_text, is_region_msg, timestamp); - if (log2file) - { - logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text); - } + addToHistory(session_id, from_name, from_id, utf8_text, is_region_msg, timestamp); + if (log2file) + { + logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text); + } - session->mNumUnread++; + session->mNumUnread++; - //update count of unread messages from real participant - if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from) - // we should increment counter for interactive system messages() - || INTERACTIVE_SYSTEM_FROM == from) - { - ++(session->mParticipantUnreadMessageCount); - } + //update count of unread messages from real participant + if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from) + // we should increment counter for interactive system messages() + || INTERACTIVE_SYSTEM_FROM == from) + { + ++(session->mParticipantUnreadMessageCount); + } - return session; + return session; } const std::string LLIMModel::getName(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); + LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return LLTrans::getString("no_session_message"); - } + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return LLTrans::getString("no_session_message"); + } - return session->mName; + return session->mName; } const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return -1; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return -1; + } - return session->mNumUnread; + return session->mNumUnread; } const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; - return LLUUID::null; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; + return LLUUID::null; + } - return session->mOtherParticipantID; + return session->mOtherParticipantID; } EInstantMessage LLIMModel::getType(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return IM_COUNT; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return IM_COUNT; + } - return session->mType; + return session->mType; } LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; - return NULL; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; + return NULL; + } - return session->mVoiceChannel; + return session->mVoiceChannel; } LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; - return NULL; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; + return NULL; + } - return session->mSpeakers; + return session->mSpeakers; } const std::string& LLIMModel::getHistoryFileName(const LLUUID& session_id) const { - LLIMSession* session = findIMSession(session_id); - if (!session) - { - LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; - return LLStringUtil::null; - } + LLIMSession* session = findIMSession(session_id); + if (!session) + { + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; + return LLStringUtil::null; + } - return session->mHistoryFileName; + return session->mHistoryFileName; } // TODO get rid of other participant ID void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) { - std::string name; - LLAgentUI::buildFullname(name); + std::string name; + LLAgentUI::buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name, - std::string("typing"), - IM_ONLINE, - (typing ? IM_TYPING_START : IM_TYPING_STOP), - session_id); - gAgent.sendReliableMessage(); + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + std::string("typing"), + IM_ONLINE, + (typing ? IM_TYPING_START : IM_TYPING_STOP), + session_id); + gAgent.sendReliableMessage(); } void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id) { - if(session_id.notNull()) - { - std::string name; - LLAgentUI::buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name, - LLStringUtil::null, - IM_ONLINE, - IM_SESSION_LEAVE, - session_id); - gAgent.sendReliableMessage(); - } + if(session_id.notNull()) + { + std::string name; + LLAgentUI::buildFullname(name); + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + LLStringUtil::null, + IM_ONLINE, + IM_SESSION_LEAVE, + session_id); + gAgent.sendReliableMessage(); + } } //*TODO this method is better be moved to the LLIMMgr void LLIMModel::sendMessage(const std::string& utf8_text, - const LLUUID& im_session_id, - const LLUUID& other_participant_id, - EInstantMessage dialog) -{ - std::string name; - bool sent = false; - LLAgentUI::buildFullname(name); - - const LLRelationship* info = NULL; - info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); - - U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; - // Old call to send messages to SLim client, no longer supported. - //if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) - //{ - // // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. - // sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); - //} - - if(!sent) - { - // Send message normally. - - // default to IM_SESSION_SEND unless it's nothing special - in - // which case it's probably an IM to everyone. - U8 new_dialog = dialog; - - if ( dialog != IM_NOTHING_SPECIAL ) - { - new_dialog = IM_SESSION_SEND; - } - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name.c_str(), - utf8_text.c_str(), - offline, - (EInstantMessage)new_dialog, - im_session_id); - gAgent.sendReliableMessage(); - } - - bool is_group_chat = false; - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(im_session_id); - if(session) - { - is_group_chat = session->isGroupSessionType(); - } - - // If there is a mute list and this is not a group chat... - if ( LLMuteList::getInstance() && !is_group_chat) - { - // ... the target should not be in our mute list for some message types. - // Auto-remove them if present. - switch( dialog ) - { - case IM_NOTHING_SPECIAL: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. - case IM_LURE_USER: - case IM_GODLIKE_LURE_USER: - case IM_FRIENDSHIP_OFFERED: - LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); - break; - default: ; // do nothing - } - } - - if((dialog == IM_NOTHING_SPECIAL) && - (other_participant_id.notNull())) - { - // Do we have to replace the /me's here? - std::string from; - LLAgentUI::buildFullname(from); - LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text); - - //local echo for the legacy communicate panel - std::string history_echo; - LLAgentUI::buildFullname(history_echo); - - history_echo += ": " + utf8_text; - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); - if (speaker_mgr) - { - speaker_mgr->speakerChatted(gAgentID); - speaker_mgr->setSpeakerTyping(gAgentID, FALSE); - } - } - - // Add the recipient to the recent people list. - bool is_not_group_id = LLGroupMgr::getInstance()->getGroupData(other_participant_id) == NULL; - - if (is_not_group_id) - { - if( session == 0)//??? shouldn't really happen - { - LLRecentPeople::instance().add(other_participant_id); - return; - } - // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat - // (it can be also Group chat but it is checked above) - // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added - // to Recent People to prevent showing of an item with (?? ?)(?? ?), sans the spaces. See EXT-8246. - // Concrete participants will be added into this list once they sent message in chat. - if (IM_SESSION_INVITE == dialog) return; - - if (IM_SESSION_CONFERENCE_START == dialog) // outgoing ad-hoc session - { - // Add only online members of conference to recent list (EXT-8658) - addSpeakersToRecent(im_session_id); - } - else // outgoing P2P session - { - // Add the recepient of the session. - if (!session->mInitialTargetIDs.empty()) - { - LLRecentPeople::instance().add(*(session->mInitialTargetIDs.begin())); - } - } - } + const LLUUID& im_session_id, + const LLUUID& other_participant_id, + EInstantMessage dialog) +{ + std::string name; + bool sent = false; + LLAgentUI::buildFullname(name); + + const LLRelationship* info = NULL; + info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); + + U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; + // Old call to send messages to SLim client, no longer supported. + //if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) + //{ + // // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. + // sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); + //} + + if(!sent) + { + // Send message normally. + + // default to IM_SESSION_SEND unless it's nothing special - in + // which case it's probably an IM to everyone. + U8 new_dialog = dialog; + + if ( dialog != IM_NOTHING_SPECIAL ) + { + new_dialog = IM_SESSION_SEND; + } + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name.c_str(), + utf8_text.c_str(), + offline, + (EInstantMessage)new_dialog, + im_session_id); + gAgent.sendReliableMessage(); + } + + bool is_group_chat = false; + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(im_session_id); + if(session) + { + is_group_chat = session->isGroupSessionType(); + } + + // If there is a mute list and this is not a group chat... + if ( LLMuteList::getInstance() && !is_group_chat) + { + // ... the target should not be in our mute list for some message types. + // Auto-remove them if present. + switch( dialog ) + { + case IM_NOTHING_SPECIAL: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. + case IM_LURE_USER: + case IM_GODLIKE_LURE_USER: + case IM_FRIENDSHIP_OFFERED: + LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); + break; + default: ; // do nothing + } + } + + if((dialog == IM_NOTHING_SPECIAL) && + (other_participant_id.notNull())) + { + // Do we have to replace the /me's here? + std::string from; + LLAgentUI::buildFullname(from); + LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text); + + //local echo for the legacy communicate panel + std::string history_echo; + LLAgentUI::buildFullname(history_echo); + + history_echo += ": " + utf8_text; + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } + } + + // Add the recipient to the recent people list. + bool is_not_group_id = LLGroupMgr::getInstance()->getGroupData(other_participant_id) == NULL; + + if (is_not_group_id) + { + if( session == 0)//??? shouldn't really happen + { + LLRecentPeople::instance().add(other_participant_id); + return; + } + // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat + // (it can be also Group chat but it is checked above) + // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added + // to Recent People to prevent showing of an item with (?? ?)(?? ?), sans the spaces. See EXT-8246. + // Concrete participants will be added into this list once they sent message in chat. + if (IM_SESSION_INVITE == dialog) return; + + if (IM_SESSION_CONFERENCE_START == dialog) // outgoing ad-hoc session + { + // Add only online members of conference to recent list (EXT-8658) + addSpeakersToRecent(im_session_id); + } + else // outgoing P2P session + { + // Add the recepient of the session. + if (!session->mInitialTargetIDs.empty()) + { + LLRecentPeople::instance().add(*(session->mInitialTargetIDs.begin())); + } + } + } } void LLIMModel::addSpeakersToRecent(const LLUUID& im_session_id) { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); - LLSpeakerMgr::speaker_list_t speaker_list; - if(speaker_mgr != NULL) - { - speaker_mgr->getSpeakerList(&speaker_list, true); - } - for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) - { - const LLPointer& speakerp = *it; - LLRecentPeople::instance().add(speakerp->mID); - } + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + LLSpeakerMgr::speaker_list_t speaker_list; + if(speaker_mgr != NULL) + { + speaker_mgr->getSpeakerList(&speaker_list, true); + } + for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) + { + const LLPointer& speakerp = *it; + LLRecentPeople::instance().add(speakerp->mID); + } } void session_starter_helper( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - EInstantMessage im_type) + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + EInstantMessage im_type) { - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + 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, other_participant_id); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addU8Fast(_PREHASH_Dialog, im_type); - msg->addUUIDFast(_PREHASH_ID, temp_session_id); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary + msg->nextBlockFast(_PREHASH_MessageBlock); + msg->addBOOLFast(_PREHASH_FromGroup, FALSE); + msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); + msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); + msg->addU8Fast(_PREHASH_Dialog, im_type); + msg->addUUIDFast(_PREHASH_ID, temp_session_id); + msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); + std::string name; + LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, LLStringUtil::null); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); + msg->addStringFast(_PREHASH_FromAgentName, name); + msg->addStringFast(_PREHASH_Message, LLStringUtil::null); + msg->addU32Fast(_PREHASH_ParentEstateID, 0); + msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); + msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); } void start_deprecated_conference_chat( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) -{ - U8* bucket; - U8* pos; - S32 count; - S32 bucket_size; - - // *FIX: this could suffer from endian issues - count = agents_to_invite.size(); - bucket_size = UUID_BYTES * count; - bucket = new U8[bucket_size]; - pos = bucket; - - for(S32 i = 0; i < count; ++i) - { - LLUUID agent_id = agents_to_invite[i].asUUID(); + const LLUUID& temp_session_id, + const LLUUID& creator_id, + const LLUUID& other_participant_id, + const LLSD& agents_to_invite) +{ + U8* bucket; + U8* pos; + S32 count; + S32 bucket_size; + + // *FIX: this could suffer from endian issues + count = agents_to_invite.size(); + bucket_size = UUID_BYTES * count; + bucket = new U8[bucket_size]; + pos = bucket; + + for(S32 i = 0; i < count; ++i) + { + LLUUID agent_id = agents_to_invite[i].asUUID(); - memcpy(pos, &agent_id, UUID_BYTES); - pos += UUID_BYTES; - } + memcpy(pos, &agent_id, UUID_BYTES); + pos += UUID_BYTES; + } - session_starter_helper( - temp_session_id, - other_participant_id, - IM_SESSION_CONFERENCE_START); + session_starter_helper( + temp_session_id, + other_participant_id, + IM_SESSION_CONFERENCE_START); - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - bucket, - bucket_size); + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + bucket, + bucket_size); - gAgent.sendReliableMessage(); + gAgent.sendReliableMessage(); - delete[] bucket; + delete[] bucket; } // Returns true if any messages were sent, false otherwise. // Is sort of equivalent to "does the server need to do anything?" bool LLIMModel::sendStartSession( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - const uuid_vec_t& ids, - EInstantMessage dialog) -{ - if ( dialog == IM_SESSION_GROUP_START ) - { - session_starter_helper( - temp_session_id, - other_participant_id, - dialog); - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); - gAgent.sendReliableMessage(); - - return true; - } - else if ( dialog == IM_SESSION_CONFERENCE_START ) - { - LLSD agents; - for (int i = 0; i < (S32) ids.size(); i++) - { - agents.append(ids[i]); - } - - //we have a new way of starting conference calls now - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string url = region->getCapability( - "ChatSessionRequest"); + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + const uuid_vec_t& ids, + EInstantMessage dialog) +{ + if ( dialog == IM_SESSION_GROUP_START ) + { + session_starter_helper( + temp_session_id, + other_participant_id, + dialog); + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); + gAgent.sendReliableMessage(); + + return true; + } + else if ( dialog == IM_SESSION_CONFERENCE_START ) + { + LLSD agents; + for (int i = 0; i < (S32) ids.size(); i++) + { + agents.append(ids[i]); + } + + //we have a new way of starting conference calls now + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string url = region->getCapability( + "ChatSessionRequest"); LLCoros::instance().launch("startConfrenceCoro", boost::bind(&startConfrenceCoro, url, temp_session_id, gAgent.getID(), other_participant_id, agents)); - } - else - { - start_deprecated_conference_chat( - temp_session_id, - gAgent.getID(), - other_participant_id, - agents); - } + } + else + { + start_deprecated_conference_chat( + temp_session_id, + gAgent.getID(), + other_participant_id, + agents); + } - //we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id) - return true; - } + //we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id) + return true; + } - return false; + return false; } @@ -2075,126 +2075,126 @@ bool LLIMModel::sendStartSession( // static LLUUID LLIMMgr::computeSessionID( - EInstantMessage dialog, - const LLUUID& other_participant_id) -{ - LLUUID session_id; - if (IM_SESSION_GROUP_START == dialog) - { - // slam group session_id to the group_id (other_participant_id) - session_id = other_participant_id; - } - else if (IM_SESSION_CONFERENCE_START == dialog) - { - session_id.generate(); - } - else if (IM_SESSION_INVITE == dialog) - { - // use provided session id for invites - session_id = other_participant_id; - } - else - { - LLUUID agent_id = gAgent.getID(); - if (other_participant_id == agent_id) - { - // if we try to send an IM to ourselves then the XOR would be null - // so we just make the session_id the same as the agent_id - session_id = agent_id; - } - else - { - // peer-to-peer or peer-to-asset session_id is the XOR - session_id = other_participant_id ^ agent_id; - } - } - - if (gAgent.isInGroup(session_id, TRUE) && (session_id != other_participant_id)) - { - LL_WARNS() << "Group session id different from group id: IM type = " << dialog << ", session id = " << session_id << ", group id = " << other_participant_id << LL_ENDL; - } - return session_id; + EInstantMessage dialog, + const LLUUID& other_participant_id) +{ + LLUUID session_id; + if (IM_SESSION_GROUP_START == dialog) + { + // slam group session_id to the group_id (other_participant_id) + session_id = other_participant_id; + } + else if (IM_SESSION_CONFERENCE_START == dialog) + { + session_id.generate(); + } + else if (IM_SESSION_INVITE == dialog) + { + // use provided session id for invites + session_id = other_participant_id; + } + else + { + LLUUID agent_id = gAgent.getID(); + if (other_participant_id == agent_id) + { + // if we try to send an IM to ourselves then the XOR would be null + // so we just make the session_id the same as the agent_id + session_id = agent_id; + } + else + { + // peer-to-peer or peer-to-asset session_id is the XOR + session_id = other_participant_id ^ agent_id; + } + } + + if (gAgent.isInGroup(session_id, TRUE) && (session_id != other_participant_id)) + { + LL_WARNS() << "Group session id different from group id: IM type = " << dialog << ", session id = " << session_id << ", group id = " << other_participant_id << LL_ENDL; + } + return session_id; } void LLIMMgr::showSessionStartError( - const std::string& error_string, - const LLUUID session_id) + const std::string& error_string, + const LLUUID session_id) { - if (!hasSession(session_id)) return; + if (!hasSession(session_id)) return; - LLSD args; - args["REASON"] = LLTrans::getString(error_string); - args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); + LLSD args; + args["REASON"] = LLTrans::getString(error_string); + args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); - LLSD payload; - payload["session_id"] = session_id; + LLSD payload; + payload["session_id"] = session_id; - LLNotificationsUtil::add( - "ChatterBoxSessionStartError", - args, - payload, - LLIMMgr::onConfirmForceCloseError); + LLNotificationsUtil::add( + "ChatterBoxSessionStartError", + args, + payload, + LLIMMgr::onConfirmForceCloseError); } void LLIMMgr::showSessionEventError( - const std::string& event_string, - const std::string& error_string, - const LLUUID session_id) + const std::string& event_string, + const std::string& error_string, + const LLUUID session_id) { - LLSD args; - LLStringUtil::format_map_t event_args; + LLSD args; + LLStringUtil::format_map_t event_args; - event_args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); + event_args["RECIPIENT"] = LLIMModel::getInstance()->getName(session_id); - args["REASON"] = - LLTrans::getString(error_string); - args["EVENT"] = - LLTrans::getString(event_string, event_args); + args["REASON"] = + LLTrans::getString(error_string); + args["EVENT"] = + LLTrans::getString(event_string, event_args); - LLNotificationsUtil::add( - "ChatterBoxSessionEventError", - args); + LLNotificationsUtil::add( + "ChatterBoxSessionEventError", + args); } void LLIMMgr::showSessionForceClose( - const std::string& reason_string, - const LLUUID session_id) + const std::string& reason_string, + const LLUUID session_id) { - if (!hasSession(session_id)) return; + if (!hasSession(session_id)) return; - LLSD args; + LLSD args; - args["NAME"] = LLIMModel::getInstance()->getName(session_id); - args["REASON"] = LLTrans::getString(reason_string); + args["NAME"] = LLIMModel::getInstance()->getName(session_id); + args["REASON"] = LLTrans::getString(reason_string); - LLSD payload; - payload["session_id"] = session_id; + LLSD payload; + payload["session_id"] = session_id; - LLNotificationsUtil::add( - "ForceCloseChatterBoxSession", - args, - payload, - LLIMMgr::onConfirmForceCloseError); + LLNotificationsUtil::add( + "ForceCloseChatterBoxSession", + args, + payload, + LLIMMgr::onConfirmForceCloseError); } //static bool LLIMMgr::onConfirmForceCloseError( - const LLSD& notification, - const LLSD& response) + const LLSD& notification, + const LLSD& response) { - //only 1 option really - LLUUID session_id = notification["payload"]["session_id"]; + //only 1 option really + LLUUID session_id = notification["payload"]["session_id"]; - LLFloater* floater = LLFloaterIMSession::findInstance(session_id); - if ( floater ) - { - floater->closeFloater(FALSE); - } - return false; + LLFloater* floater = LLFloaterIMSession::findInstance(session_id); + if ( floater ) + { + floater->closeFloater(FALSE); + } + return false; } @@ -2216,7 +2216,7 @@ LLCallDialogManager::~LLCallDialogManager() void LLCallDialogManager::initSingleton() { - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(LLCallDialogManager::onVoiceChannelChanged); + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(LLCallDialogManager::onVoiceChannelChanged); } // static @@ -2227,48 +2227,48 @@ void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id) void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id) { - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); - if(!session) - { - mPreviousSessionlName = mCurrentSessionlName; - mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution - return; - } - - mSession = session; - - static boost::signals2::connection prev_channel_state_changed_connection; - // disconnect previously connected callback to avoid have invalid sSession in onVoiceChannelStateChanged() - prev_channel_state_changed_connection.disconnect(); - prev_channel_state_changed_connection = - mSession->mVoiceChannel->setStateChangedCallback(boost::bind(LLCallDialogManager::onVoiceChannelStateChanged, _1, _2, _3, _4)); - - if(mCurrentSessionlName != session->mName) - { - mPreviousSessionlName = mCurrentSessionlName; - mCurrentSessionlName = session->mName; - } - - if (LLVoiceChannel::getCurrentVoiceChannel()->getState() == LLVoiceChannel::STATE_CALL_STARTED && - LLVoiceChannel::getCurrentVoiceChannel()->getCallDirection() == LLVoiceChannel::OUTGOING_CALL) - { - - //*TODO get rid of duplicated code - LLSD mCallDialogPayload; - mCallDialogPayload["session_id"] = mSession->mSessionID; - mCallDialogPayload["session_name"] = mSession->mName; - mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; - mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; - mCallDialogPayload["state"] = LLVoiceChannel::STATE_CALL_STARTED; - mCallDialogPayload["disconnected_channel_name"] = mSession->mName; - mCallDialogPayload["session_type"] = mSession->mSessionType; - - LLOutgoingCallDialog* ocd = LLFloaterReg::getTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if(ocd) - { - ocd->show(mCallDialogPayload); - } - } + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if(!session) + { + mPreviousSessionlName = mCurrentSessionlName; + mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution + return; + } + + mSession = session; + + static boost::signals2::connection prev_channel_state_changed_connection; + // disconnect previously connected callback to avoid have invalid sSession in onVoiceChannelStateChanged() + prev_channel_state_changed_connection.disconnect(); + prev_channel_state_changed_connection = + mSession->mVoiceChannel->setStateChangedCallback(boost::bind(LLCallDialogManager::onVoiceChannelStateChanged, _1, _2, _3, _4)); + + if(mCurrentSessionlName != session->mName) + { + mPreviousSessionlName = mCurrentSessionlName; + mCurrentSessionlName = session->mName; + } + + if (LLVoiceChannel::getCurrentVoiceChannel()->getState() == LLVoiceChannel::STATE_CALL_STARTED && + LLVoiceChannel::getCurrentVoiceChannel()->getCallDirection() == LLVoiceChannel::OUTGOING_CALL) + { + + //*TODO get rid of duplicated code + LLSD mCallDialogPayload; + mCallDialogPayload["session_id"] = mSession->mSessionID; + mCallDialogPayload["session_name"] = mSession->mName; + mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; + mCallDialogPayload["state"] = LLVoiceChannel::STATE_CALL_STARTED; + mCallDialogPayload["disconnected_channel_name"] = mSession->mName; + mCallDialogPayload["session_type"] = mSession->mSessionType; + + LLOutgoingCallDialog* ocd = LLFloaterReg::getTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if(ocd) + { + ocd->show(mCallDialogPayload); + } + } } @@ -2280,116 +2280,116 @@ void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EStat void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent) { - LLSD mCallDialogPayload; - LLOutgoingCallDialog* ocd = NULL; - - if(mOldState == new_state) - { - return; - } - - mOldState = new_state; - - mCallDialogPayload["session_id"] = mSession->mSessionID; - mCallDialogPayload["session_name"] = mSession->mName; - mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; - mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; - mCallDialogPayload["state"] = new_state; - mCallDialogPayload["disconnected_channel_name"] = mSession->mName; - mCallDialogPayload["session_type"] = mSession->mSessionType; - mCallDialogPayload["ended_by_agent"] = ended_by_agent; - - switch(new_state) - { - case LLVoiceChannel::STATE_CALL_STARTED : - // do not show "Calling to..." if it is incoming call - if(direction == LLVoiceChannel::INCOMING_CALL) - { - return; - } - break; - - case LLVoiceChannel::STATE_HUNG_UP: - // this state is coming before session is changed - break; - - case LLVoiceChannel::STATE_CONNECTED : - ocd = LLFloaterReg::findTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if (ocd) - { - ocd->closeFloater(); - } - return; - - default: - break; - } - - ocd = LLFloaterReg::getTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if(ocd) - { - ocd->show(mCallDialogPayload); - } + LLSD mCallDialogPayload; + LLOutgoingCallDialog* ocd = NULL; + + if(mOldState == new_state) + { + return; + } + + mOldState = new_state; + + mCallDialogPayload["session_id"] = mSession->mSessionID; + mCallDialogPayload["session_name"] = mSession->mName; + mCallDialogPayload["other_user_id"] = mSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = mPreviousSessionlName; + mCallDialogPayload["state"] = new_state; + mCallDialogPayload["disconnected_channel_name"] = mSession->mName; + mCallDialogPayload["session_type"] = mSession->mSessionType; + mCallDialogPayload["ended_by_agent"] = ended_by_agent; + + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + // do not show "Calling to..." if it is incoming call + if(direction == LLVoiceChannel::INCOMING_CALL) + { + return; + } + break; + + case LLVoiceChannel::STATE_HUNG_UP: + // this state is coming before session is changed + break; + + case LLVoiceChannel::STATE_CONNECTED : + ocd = LLFloaterReg::findTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if (ocd) + { + ocd->closeFloater(); + } + return; + + default: + break; + } + + ocd = LLFloaterReg::getTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if(ocd) + { + ocd->show(mCallDialogPayload); + } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LLCallDialog::LLCallDialog(const LLSD& payload) - : LLDockableFloater(NULL, false, payload), + : LLDockableFloater(NULL, false, payload), - mPayload(payload), - mLifetime(DEFAULT_LIFETIME) + mPayload(payload), + mLifetime(DEFAULT_LIFETIME) { - setAutoFocus(FALSE); - // force docked state since this floater doesn't save it between recreations - setDocked(true); + setAutoFocus(FALSE); + // force docked state since this floater doesn't save it between recreations + setDocked(true); } LLCallDialog::~LLCallDialog() { - LLUI::getInstance()->removePopup(this); + LLUI::getInstance()->removePopup(this); } BOOL LLCallDialog::postBuild() { - if (!LLDockableFloater::postBuild() || !gToolBarView) - return FALSE; + if (!LLDockableFloater::postBuild() || !gToolBarView) + return FALSE; - dockToToolbarButton("speak"); + dockToToolbarButton("speak"); - return TRUE; + return TRUE; } void LLCallDialog::dockToToolbarButton(const std::string& toolbarButtonName) { - LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName); - LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName); + LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName); + LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName); - setUseTongue(anchor_panel); + setUseTongue(anchor_panel); - setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos)); + setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos)); } LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarButtonName) { - LLCommandId command_id(toolbarButtonName); - S32 toolbar_loc = gToolBarView->hasCommand(command_id); + LLCommandId command_id(toolbarButtonName); + S32 toolbar_loc = gToolBarView->hasCommand(command_id); - LLDockControl::DocAt doc_at = LLDockControl::TOP; + LLDockControl::DocAt doc_at = LLDockControl::TOP; - switch (toolbar_loc) - { - case LLToolBarEnums::TOOLBAR_LEFT: - doc_at = LLDockControl::RIGHT; - break; + switch (toolbar_loc) + { + case LLToolBarEnums::TOOLBAR_LEFT: + doc_at = LLDockControl::RIGHT; + break; - case LLToolBarEnums::TOOLBAR_RIGHT: - doc_at = LLDockControl::LEFT; - break; - } + case LLToolBarEnums::TOOLBAR_RIGHT: + doc_at = LLDockControl::LEFT; + break; + } - return doc_at; + return doc_at; } @@ -2399,237 +2399,237 @@ LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarB LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : LLCallDialog(payload) { - LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); - if(instance && instance->getVisible()) - { - instance->onCancel(instance); - } + LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance("outgoing_call", LLOutgoingCallDialog::OCD_KEY); + if(instance && instance->getVisible()) + { + instance->onCancel(instance); + } } void LLCallDialog::draw() { - if (lifetimeHasExpired()) - { - onLifetimeExpired(); - } + if (lifetimeHasExpired()) + { + onLifetimeExpired(); + } - if (getDockControl() != NULL) - { - LLDockableFloater::draw(); - } + if (getDockControl() != NULL) + { + LLDockableFloater::draw(); + } } // virtual void LLCallDialog::onOpen(const LLSD& key) { - LLDockableFloater::onOpen(key); + LLDockableFloater::onOpen(key); - // it should be over the all floaters. EXT-5116 - LLUI::getInstance()->addPopup(this); + // it should be over the all floaters. EXT-5116 + LLUI::getInstance()->addPopup(this); } void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id) { - bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); + bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); - bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE); + bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE); - LLAvatarIconCtrl* avatar_icon = getChild("avatar_icon"); - LLGroupIconCtrl* group_icon = getChild("group_icon"); + LLAvatarIconCtrl* avatar_icon = getChild("avatar_icon"); + LLGroupIconCtrl* group_icon = getChild("group_icon"); - avatar_icon->setVisible(!is_group); - group_icon->setVisible(is_group); + avatar_icon->setVisible(!is_group); + group_icon->setVisible(is_group); - if (is_group) - { - group_icon->setValue(session_id); - } - else if (participant_is_avatar) - { - avatar_icon->setValue(participant_id); - } - else - { + if (is_group) + { + group_icon->setValue(session_id); + } + else if (participant_is_avatar) + { + avatar_icon->setValue(participant_id); + } + else + { LL_WARNS() << "Participant neither avatar nor group" << LL_ENDL; group_icon->setValue(session_id); - } + } } bool LLCallDialog::lifetimeHasExpired() { - if (mLifetimeTimer.getStarted()) - { - F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); - if (elapsed_time > mLifetime) - { - return true; - } - } - return false; + if (mLifetimeTimer.getStarted()) + { + F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); + if (elapsed_time > mLifetime) + { + return true; + } + } + return false; } void LLCallDialog::onLifetimeExpired() { - mLifetimeTimer.stop(); - closeFloater(); + mLifetimeTimer.stop(); + closeFloater(); } void LLOutgoingCallDialog::show(const LLSD& key) { - mPayload = key; - - //will be false only if voice in parcel is disabled and channel we leave is nearby(checked further) - bool show_oldchannel = LLViewerParcelMgr::getInstance()->allowAgentVoice(); - - // hide all text at first - hideAllText(); - - // init notification's lifetime - std::istringstream ss( getString("lifetime") ); - if (!(ss >> mLifetime)) - { - mLifetime = DEFAULT_LIFETIME; - } - - // customize text strings - // tell the user which voice channel they are leaving - if (!mPayload["old_channel_name"].asString().empty()) - { - std::string old_caller_name = mPayload["old_channel_name"].asString(); - - getChild("leaving")->setTextArg("[CURRENT_CHAT]", old_caller_name); - show_oldchannel = true; - } - else - { - getChild("leaving")->setTextArg("[CURRENT_CHAT]", getString("localchat")); - } - - if (!mPayload["disconnected_channel_name"].asString().empty()) - { - std::string channel_name = mPayload["disconnected_channel_name"].asString(); - getChild("nearby")->setTextArg("[VOICE_CHANNEL_NAME]", channel_name); - - // skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice, - // so no reconnection to nearby chat happens (EXT-4397) - bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); - std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string(); - getChild("nearby")->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); - - const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; - getChild(nearby_str)->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); - } - - std::string callee_name = mPayload["session_name"].asString(); - - if (callee_name == "anonymous") // obsolete? Likely was part of avaline support - { - callee_name = getString("anonymous"); - } - - LLSD callee_id = mPayload["other_user_id"]; - // Beautification: Since you know who you called, just show display name - std::string title = callee_name; - std::string final_callee_name = callee_name; - if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(callee_id, &av_name)) - { - final_callee_name = av_name.getDisplayName(); - title = av_name.getCompleteName(); - } - } - getChild("calling")->setTextArg("[CALLEE_NAME]", final_callee_name); - getChild("connecting")->setTextArg("[CALLEE_NAME]", final_callee_name); - - setTitle(title); - - // for outgoing group calls callee_id == group id == session id - setIcon(callee_id, callee_id); - - // stop timer by default - mLifetimeTimer.stop(); - - // show only necessary strings and controls - switch(mPayload["state"].asInteger()) - { - case LLVoiceChannel::STATE_CALL_STARTED : - getChild("calling")->setVisible(true); - getChild("Cancel")->setVisible(true); - if(show_oldchannel) - { - getChild("leaving")->setVisible(true); - } - break; - // STATE_READY is here to show appropriate text for ad-hoc and group calls when floater is shown(EXT-6893) - case LLVoiceChannel::STATE_READY : - case LLVoiceChannel::STATE_RINGING : - if(show_oldchannel) - { - getChild("leaving")->setVisible(true); - } - getChild("connecting")->setVisible(true); - break; - case LLVoiceChannel::STATE_ERROR : - getChild("noanswer")->setVisible(true); - getChild("Cancel")->setVisible(false); - setCanClose(true); - mLifetimeTimer.start(); - break; - case LLVoiceChannel::STATE_HUNG_UP : - if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) - { - const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; - getChild(nearby_str)->setVisible(true); - } - else - { - getChild("nearby")->setVisible(true); - } - getChild("Cancel")->setVisible(false); - setCanClose(true); - mLifetimeTimer.start(); - } - - openFloater(LLOutgoingCallDialog::OCD_KEY); + mPayload = key; + + //will be false only if voice in parcel is disabled and channel we leave is nearby(checked further) + bool show_oldchannel = LLViewerParcelMgr::getInstance()->allowAgentVoice(); + + // hide all text at first + hideAllText(); + + // init notification's lifetime + std::istringstream ss( getString("lifetime") ); + if (!(ss >> mLifetime)) + { + mLifetime = DEFAULT_LIFETIME; + } + + // customize text strings + // tell the user which voice channel they are leaving + if (!mPayload["old_channel_name"].asString().empty()) + { + std::string old_caller_name = mPayload["old_channel_name"].asString(); + + getChild("leaving")->setTextArg("[CURRENT_CHAT]", old_caller_name); + show_oldchannel = true; + } + else + { + getChild("leaving")->setTextArg("[CURRENT_CHAT]", getString("localchat")); + } + + if (!mPayload["disconnected_channel_name"].asString().empty()) + { + std::string channel_name = mPayload["disconnected_channel_name"].asString(); + getChild("nearby")->setTextArg("[VOICE_CHANNEL_NAME]", channel_name); + + // skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice, + // so no reconnection to nearby chat happens (EXT-4397) + bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); + std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string(); + getChild("nearby")->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); + + const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; + getChild(nearby_str)->setTextArg("[RECONNECT_NEARBY]", reconnect_nearby); + } + + std::string callee_name = mPayload["session_name"].asString(); + + if (callee_name == "anonymous") // obsolete? Likely was part of avaline support + { + callee_name = getString("anonymous"); + } + + LLSD callee_id = mPayload["other_user_id"]; + // Beautification: Since you know who you called, just show display name + std::string title = callee_name; + std::string final_callee_name = callee_name; + if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(callee_id, &av_name)) + { + final_callee_name = av_name.getDisplayName(); + title = av_name.getCompleteName(); + } + } + getChild("calling")->setTextArg("[CALLEE_NAME]", final_callee_name); + getChild("connecting")->setTextArg("[CALLEE_NAME]", final_callee_name); + + setTitle(title); + + // for outgoing group calls callee_id == group id == session id + setIcon(callee_id, callee_id); + + // stop timer by default + mLifetimeTimer.stop(); + + // show only necessary strings and controls + switch(mPayload["state"].asInteger()) + { + case LLVoiceChannel::STATE_CALL_STARTED : + getChild("calling")->setVisible(true); + getChild("Cancel")->setVisible(true); + if(show_oldchannel) + { + getChild("leaving")->setVisible(true); + } + break; + // STATE_READY is here to show appropriate text for ad-hoc and group calls when floater is shown(EXT-6893) + case LLVoiceChannel::STATE_READY : + case LLVoiceChannel::STATE_RINGING : + if(show_oldchannel) + { + getChild("leaving")->setVisible(true); + } + getChild("connecting")->setVisible(true); + break; + case LLVoiceChannel::STATE_ERROR : + getChild("noanswer")->setVisible(true); + getChild("Cancel")->setVisible(false); + setCanClose(true); + mLifetimeTimer.start(); + break; + case LLVoiceChannel::STATE_HUNG_UP : + if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) + { + const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER; + getChild(nearby_str)->setVisible(true); + } + else + { + getChild("nearby")->setVisible(true); + } + getChild("Cancel")->setVisible(false); + setCanClose(true); + mLifetimeTimer.start(); + } + + openFloater(LLOutgoingCallDialog::OCD_KEY); } void LLOutgoingCallDialog::hideAllText() { - getChild("calling")->setVisible(false); - getChild("leaving")->setVisible(false); - getChild("connecting")->setVisible(false); - getChild("nearby_P2P_by_other")->setVisible(false); - getChild("nearby_P2P_by_agent")->setVisible(false); - getChild("nearby")->setVisible(false); - getChild("noanswer")->setVisible(false); + getChild("calling")->setVisible(false); + getChild("leaving")->setVisible(false); + getChild("connecting")->setVisible(false); + getChild("nearby_P2P_by_other")->setVisible(false); + getChild("nearby_P2P_by_agent")->setVisible(false); + getChild("nearby")->setVisible(false); + getChild("noanswer")->setVisible(false); } //static void LLOutgoingCallDialog::onCancel(void* user_data) { - LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; + LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; - if (!gIMMgr) - return; + if (!gIMMgr) + return; - LLUUID session_id = self->mPayload["session_id"].asUUID(); - gIMMgr->endCall(session_id); + LLUUID session_id = self->mPayload["session_id"].asUUID(); + gIMMgr->endCall(session_id); - self->closeFloater(); + self->closeFloater(); } BOOL LLOutgoingCallDialog::postBuild() { - BOOL success = LLCallDialog::postBuild(); + BOOL success = LLCallDialog::postBuild(); - childSetAction("Cancel", onCancel, this); + childSetAction("Cancel", onCancel, this); - setCanDrag(FALSE); + setCanDrag(FALSE); - return success; + return success; } @@ -2658,26 +2658,26 @@ mAvatarNameCacheConnection() void LLIncomingCallDialog::onLifetimeExpired() { - std::string session_handle = mPayload["session_handle"].asString(); - if (LLVoiceClient::getInstance()->isValidChannel(session_handle)) - { - // restart notification's timer if call is still valid - mLifetimeTimer.start(); - } - else - { - // close invitation if call is already not valid - mLifetimeTimer.stop(); - LLUUID session_id = mPayload["session_id"].asUUID(); - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - closeFloater(); - } + std::string session_handle = mPayload["session_handle"].asString(); + if (LLVoiceClient::getInstance()->isValidChannel(session_handle)) + { + // restart notification's timer if call is still valid + mLifetimeTimer.start(); + } + else + { + // close invitation if call is already not valid + mLifetimeTimer.stop(); + LLUUID session_id = mPayload["session_id"].asUUID(); + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + closeFloater(); + } } BOOL LLIncomingCallDialog::postBuild() { - LLCallDialog::postBuild(); + LLCallDialog::postBuild(); if (!mPayload.isMap() || mPayload.size() == 0) { @@ -2685,9 +2685,9 @@ BOOL LLIncomingCallDialog::postBuild() return TRUE; } - LLUUID session_id = mPayload["session_id"].asUUID(); - LLSD caller_id = mPayload["caller_id"]; - std::string caller_name = mPayload["caller_name"].asString(); + LLUUID session_id = mPayload["session_id"].asUUID(); + LLSD caller_id = mPayload["caller_id"]; + std::string caller_name = mPayload["caller_name"].asString(); if (session_id.isNull() && caller_id.asUUID().isNull()) { @@ -2702,347 +2702,347 @@ BOOL LLIncomingCallDialog::postBuild() return TRUE; } - // init notification's lifetime - std::istringstream ss( getString("lifetime") ); - if (!(ss >> mLifetime)) - { - mLifetime = DEFAULT_LIFETIME; - } - - std::string call_type; - if (gAgent.isInGroup(session_id, TRUE)) - { - LLStringUtil::format_map_t args; - LLGroupData data; - if (gAgent.getGroupData(session_id, data)) - { - args["[GROUP]"] = data.mName; - call_type = getString(notify_box_type, args); - } - } - else - { - call_type = getString(notify_box_type); - } - - if (caller_name == "anonymous") // obsolete? Likely was part of avaline support - { - caller_name = getString("anonymous"); - setCallerName(caller_name, caller_name, call_type); - } - else - { - // Get the full name information - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - mAvatarNameCacheConnection = LLAvatarNameCache::get(caller_id, boost::bind(&LLIncomingCallDialog::onAvatarNameCache, this, _1, _2, call_type)); - } - - setIcon(session_id, caller_id); - - childSetAction("Accept", onAccept, this); - childSetAction("Reject", onReject, this); - childSetAction("Start IM", onStartIM, this); - setDefaultBtn("Accept"); - - if(notify_box_type != "VoiceInviteGroup" && notify_box_type != "VoiceInviteAdHoc") - { - // starting notification's timer for P2P invitations - mLifetimeTimer.start(); - } - else - { - mLifetimeTimer.stop(); - } - - //it's not possible to connect to existing Ad-Hoc/Group chat through incoming ad-hoc call - bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); - getChildView("Start IM")->setVisible( is_avatar && notify_box_type != "VoiceInviteAdHoc" && notify_box_type != "VoiceInviteGroup"); - - setCanDrag(FALSE); - return TRUE; + // init notification's lifetime + std::istringstream ss( getString("lifetime") ); + if (!(ss >> mLifetime)) + { + mLifetime = DEFAULT_LIFETIME; + } + + std::string call_type; + if (gAgent.isInGroup(session_id, TRUE)) + { + LLStringUtil::format_map_t args; + LLGroupData data; + if (gAgent.getGroupData(session_id, data)) + { + args["[GROUP]"] = data.mName; + call_type = getString(notify_box_type, args); + } + } + else + { + call_type = getString(notify_box_type); + } + + if (caller_name == "anonymous") // obsolete? Likely was part of avaline support + { + caller_name = getString("anonymous"); + setCallerName(caller_name, caller_name, call_type); + } + else + { + // Get the full name information + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + mAvatarNameCacheConnection = LLAvatarNameCache::get(caller_id, boost::bind(&LLIncomingCallDialog::onAvatarNameCache, this, _1, _2, call_type)); + } + + setIcon(session_id, caller_id); + + childSetAction("Accept", onAccept, this); + childSetAction("Reject", onReject, this); + childSetAction("Start IM", onStartIM, this); + setDefaultBtn("Accept"); + + if(notify_box_type != "VoiceInviteGroup" && notify_box_type != "VoiceInviteAdHoc") + { + // starting notification's timer for P2P invitations + mLifetimeTimer.start(); + } + else + { + mLifetimeTimer.stop(); + } + + //it's not possible to connect to existing Ad-Hoc/Group chat through incoming ad-hoc call + bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); + getChildView("Start IM")->setVisible( is_avatar && notify_box_type != "VoiceInviteAdHoc" && notify_box_type != "VoiceInviteGroup"); + + setCanDrag(FALSE); + return TRUE; } void LLIncomingCallDialog::setCallerName(const std::string& ui_title, - const std::string& ui_label, - const std::string& call_type) + const std::string& ui_label, + const std::string& call_type) { - // call_type may be a string like " is calling." - LLUICtrl* caller_name_widget = getChild("caller name"); - caller_name_widget->setValue(ui_label + " " + call_type); + // call_type may be a string like " is calling." + LLUICtrl* caller_name_widget = getChild("caller name"); + caller_name_widget->setValue(ui_label + " " + call_type); } void LLIncomingCallDialog::onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name, - const std::string& call_type) + const LLAvatarName& av_name, + const std::string& call_type) { - mAvatarNameCacheConnection.disconnect(); - std::string title = av_name.getCompleteName(); - setCallerName(title, av_name.getCompleteName(), call_type); + mAvatarNameCacheConnection.disconnect(); + std::string title = av_name.getCompleteName(); + setCallerName(title, av_name.getCompleteName(), call_type); } void LLIncomingCallDialog::onOpen(const LLSD& key) { - LLCallDialog::onOpen(key); + LLCallDialog::onOpen(key); - if (gSavedSettings.getBOOL("PlaySoundIncomingVoiceCall")) - { - // play a sound for incoming voice call if respective property is set - make_ui_sound("UISndStartIM"); - } + if (gSavedSettings.getBOOL("PlaySoundIncomingVoiceCall")) + { + // play a sound for incoming voice call if respective property is set + make_ui_sound("UISndStartIM"); + } - LLStringUtil::format_map_t args; - LLGroupData data; - // if it's a group call, retrieve group name to use it in question - if (gAgent.getGroupData(key["session_id"].asUUID(), data)) - { - args["[GROUP]"] = data.mName; - } + LLStringUtil::format_map_t args; + LLGroupData data; + // if it's a group call, retrieve group name to use it in question + if (gAgent.getGroupData(key["session_id"].asUUID(), data)) + { + args["[GROUP]"] = data.mName; + } } //static void LLIncomingCallDialog::onAccept(void* user_data) { - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - processCallResponse(0, self->mPayload); - self->closeFloater(); + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + processCallResponse(0, self->mPayload); + self->closeFloater(); } //static void LLIncomingCallDialog::onReject(void* user_data) { - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - processCallResponse(1, self->mPayload); - self->closeFloater(); + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + processCallResponse(1, self->mPayload); + self->closeFloater(); } //static void LLIncomingCallDialog::onStartIM(void* user_data) { - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - processCallResponse(2, self->mPayload); - self->closeFloater(); + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + processCallResponse(2, self->mPayload); + self->closeFloater(); } // static void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload) { - if (!gIMMgr || gDisconnected) - return; - - LLUUID session_id = payload["session_id"].asUUID(); - LLUUID caller_id = payload["caller_id"].asUUID(); - std::string session_name = payload["session_name"].asString(); - EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); - LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); - bool voice = true; - switch(response) - { - case 2: // start IM: just don't start the voice chat - { - voice = false; - /* FALLTHROUGH */ - } - case 0: // accept - { - if (type == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - session_id = gIMMgr->addP2PSession( - session_name, - caller_id, - payload["session_handle"].asString(), - payload["session_uri"].asString()); - - if (voice) - { - gIMMgr->startCall(session_id, LLVoiceChannel::INCOMING_CALL); - } - else - { - LLAvatarActions::startIM(caller_id); - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } - else - { - //session name should not be empty, but it can contain spaces so we don't trim - std::string correct_session_name = session_name; - if (session_name.empty()) - { - LL_WARNS() << "Received an empty session name from a server" << LL_ENDL; - - switch(type){ - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_GROUP_START: - case IM_SESSION_INVITE: - if (gAgent.isInGroup(session_id, TRUE)) - { - LLGroupData data; - if (!gAgent.getGroupData(session_id, data)) break; - correct_session_name = data.mName; - } - else - { - // *NOTE: really should be using callbacks here - LLAvatarName av_name; - if (LLAvatarNameCache::get(caller_id, &av_name)) - { - correct_session_name = av_name.getCompleteName(); - correct_session_name.append(ADHOC_NAME_SUFFIX); - } - } - LL_INFOS("IMVIEW") << "Corrected session name is " << correct_session_name << LL_ENDL; - break; - default: - LL_WARNS("IMVIEW") << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; - break; - } - } - - gIMMgr->addSession(correct_session_name, type, session_id, true); - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - if (voice) - { - LLCoros::instance().launch("chatterBoxInvitationCoro", - boost::bind(&chatterBoxInvitationCoro, url, - session_id, inv_type)); - - // send notification message to the corresponding chat - if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") - { - LLStringUtil::format_map_t string_args; - string_args["[NAME]"] = payload["caller_name"].asString(); - std::string message = LLTrans::getString("name_started_call", string_args); - LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message); - } - } - } - if (voice) - { - break; - } - } - case 1: // decline - { - if (type == IM_SESSION_P2P_INVITE) - { - if(LLVoiceClient::getInstance()) - { - std::string s = payload["session_handle"].asString(); - LLVoiceClient::getInstance()->declineInvite(s); - } - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = session_id; + if (!gIMMgr || gDisconnected) + return; - LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, - "Invitation declined", - "Invitation decline failed."); - } - } + LLUUID session_id = payload["session_id"].asUUID(); + LLUUID caller_id = payload["caller_id"].asUUID(); + std::string session_name = payload["session_name"].asString(); + EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); + bool voice = true; + switch(response) + { + case 2: // start IM: just don't start the voice chat + { + voice = false; + /* FALLTHROUGH */ + } + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + session_name, + caller_id, + payload["session_handle"].asString(), + payload["session_uri"].asString()); + + if (voice) + { + gIMMgr->startCall(session_id, LLVoiceChannel::INCOMING_CALL); + } + else + { + LLAvatarActions::startIM(caller_id); + } - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + //session name should not be empty, but it can contain spaces so we don't trim + std::string correct_session_name = session_name; + if (session_name.empty()) + { + LL_WARNS() << "Received an empty session name from a server" << LL_ENDL; + + switch(type){ + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_GROUP_START: + case IM_SESSION_INVITE: + if (gAgent.isInGroup(session_id, TRUE)) + { + LLGroupData data; + if (!gAgent.getGroupData(session_id, data)) break; + correct_session_name = data.mName; + } + else + { + // *NOTE: really should be using callbacks here + LLAvatarName av_name; + if (LLAvatarNameCache::get(caller_id, &av_name)) + { + correct_session_name = av_name.getCompleteName(); + correct_session_name.append(ADHOC_NAME_SUFFIX); + } + } + LL_INFOS("IMVIEW") << "Corrected session name is " << correct_session_name << LL_ENDL; + break; + default: + LL_WARNS("IMVIEW") << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; + break; + } + } + + gIMMgr->addSession(correct_session_name, type, session_id, true); + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + if (voice) + { + LLCoros::instance().launch("chatterBoxInvitationCoro", + boost::bind(&chatterBoxInvitationCoro, url, + session_id, inv_type)); + + // send notification message to the corresponding chat + if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") + { + LLStringUtil::format_map_t string_args; + string_args["[NAME]"] = payload["caller_name"].asString(); + std::string message = LLTrans::getString("name_started_call", string_args); + LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message); + } + } + } + if (voice) + { + break; + } + } + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + if(LLVoiceClient::getInstance()) + { + std::string s = payload["session_handle"].asString(); + LLVoiceClient::getInstance()->declineInvite(s); + } + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, + "Invitation declined", + "Invitation decline failed."); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } } bool inviteUserResponse(const LLSD& notification, const LLSD& response) { - if (!gIMMgr) - return false; - - const LLSD& payload = notification["payload"]; - LLUUID session_id = payload["session_id"].asUUID(); - EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); - LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - switch(option) - { - case 0: // accept - { - if (type == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - session_id = gIMMgr->addP2PSession( - payload["session_name"].asString(), - payload["caller_id"].asUUID(), - payload["session_handle"].asString(), - payload["session_uri"].asString()); - - gIMMgr->startCall(session_id); - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } - else - { - gIMMgr->addSession( - payload["session_name"].asString(), - type, - session_id, true); - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); + if (!gIMMgr) + return false; + + const LLSD& payload = notification["payload"]; + LLUUID session_id = payload["session_id"].asUUID(); + EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + payload["session_name"].asString(), + payload["caller_id"].asUUID(), + payload["session_handle"].asString(), + payload["session_uri"].asString()); + + gIMMgr->startCall(session_id); + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + gIMMgr->addSession( + payload["session_name"].asString(), + type, + session_id, true); + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); LLCoros::instance().launch("chatterBoxInvitationCoro", boost::bind(&chatterBoxInvitationCoro, url, session_id, inv_type)); - } - } - break; - case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) - { - // mute the sender of this invite - if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) - { - LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); - LLMuteList::getInstance()->add(mute); - } - } - /* FALLTHROUGH */ - - case 1: // decline - { - if (type == IM_SESSION_P2P_INVITE) - { - std::string s = payload["session_handle"].asString(); - LLVoiceClient::getInstance()->declineInvite(s); - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = session_id; + } + } + break; + case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) + { + // mute the sender of this invite + if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) + { + LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); + LLMuteList::getInstance()->add(mute); + } + } + /* FALLTHROUGH */ + + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + std::string s = payload["session_handle"].asString(); + LLVoiceClient::getInstance()->declineInvite(s); + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, "Invitation declined.", "Invitation decline failed."); - } - } + } + } - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - break; - } + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + break; + } - return false; + return false; } // @@ -3051,113 +3051,113 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLIMMgr::LLIMMgr() { - mPendingInvitations = LLSD::emptyMap(); - mPendingAgentListUpdates = LLSD::emptyMap(); + mPendingInvitations = LLSD::emptyMap(); + mPendingAgentListUpdates = LLSD::emptyMap(); - LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLFloaterIMSession::sRemoveTypingIndicator, _1)); + LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLFloaterIMSession::sRemoveTypingIndicator, _1)); - gSavedPerAccountSettings.declareBOOL("FetchGroupChatHistory", TRUE, "Fetch recent messages from group chat servers when a group window opens", LLControlVariable::PERSIST_ALWAYS); + gSavedPerAccountSettings.declareBOOL("FetchGroupChatHistory", TRUE, "Fetch recent messages from group chat servers when a group window opens", LLControlVariable::PERSIST_ALWAYS); } // Add a message to a session. void LLIMMgr::addMessage( - const LLUUID& session_id, - const LLUUID& target_id, - const std::string& from, - const std::string& msg, - bool is_offline_msg, - const std::string& session_name, - EInstantMessage dialog, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, + const LLUUID& session_id, + const LLUUID& target_id, + const std::string& from, + const std::string& msg, + bool is_offline_msg, + const std::string& session_name, + EInstantMessage dialog, + U32 parent_estate_id, + const LLUUID& region_id, + const LLVector3& position, bool is_region_msg, U32 timestamp) // May be zero { - LLUUID other_participant_id = target_id; - - LLUUID new_session_id = session_id; - if (new_session_id.isNull()) - { - //no session ID...compute new one - new_session_id = computeSessionID(dialog, other_participant_id); - } - - //*NOTE session_name is empty in case of incoming P2P sessions - std::string fixed_session_name = from; - bool name_is_setted = false; - if(!session_name.empty() && session_name.size()>1) - { - fixed_session_name = session_name; - name_is_setted = true; - } - bool skip_message = false; - bool from_linden = LLMuteList::isLinden(from); + LLUUID other_participant_id = target_id; + + LLUUID new_session_id = session_id; + if (new_session_id.isNull()) + { + //no session ID...compute new one + new_session_id = computeSessionID(dialog, other_participant_id); + } + + //*NOTE session_name is empty in case of incoming P2P sessions + std::string fixed_session_name = from; + bool name_is_setted = false; + if(!session_name.empty() && session_name.size()>1) + { + fixed_session_name = session_name; + name_is_setted = true; + } + bool skip_message = false; + bool from_linden = LLMuteList::isLinden(from); if (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && !from_linden) - { - // Evaluate if we need to skip this message when that setting is true (default is false) - skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... - skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself - } - - bool new_session = !hasSession(new_session_id); - if (new_session) - { - // Group chat session was initiated by muted resident, do not start this session viewerside - // do not send leave msg either, so we are able to get group messages from other participants - if ((IM_SESSION_INVITE == dialog) && gAgent.isInGroup(new_session_id) && - LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) - { - return; - } - - LLAvatarName av_name; - if (LLAvatarNameCache::get(other_participant_id, &av_name) && !name_is_setted) - { - fixed_session_name = av_name.getDisplayName(); - } - LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); - - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); - if (session) - { - skip_message &= !session->isGroupSessionType(); // Do not skip group chats... - if (skip_message) - { - gIMMgr->leaveSession(new_session_id); - } - // When we get a new IM, and if you are a god, display a bit - // of information about the source. This is to help liaisons - // when answering questions. - if (gAgent.isGodlike()) - { - // *TODO:translate (low priority, god ability) - std::ostringstream bonus_info; - bonus_info << LLTrans::getString("***") + " " + LLTrans::getString("IMParentEstate") + ":" + " " - << parent_estate_id - << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") - << ((parent_estate_id == 5) ? "," + LLTrans::getString("IMTeen") : ""); - - // once we have web-services (or something) which returns - // information about a region id, we can print this out - // and even have it link to map-teleport or something. - //<< "*** region_id: " << region_id << std::endl - //<< "*** position: " << position << std::endl; - - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str(), true, is_region_msg); - } - - // Logically it would make more sense to reject the session sooner, in another area of the - // code, but the session has to be established inside the server before it can be left. - if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) - { - LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; - if (!gIMMgr->leaveSession(new_session_id)) - { - LL_INFOS("IMVIEW") << "Session " << new_session_id << " does not exist." << LL_ENDL; - } - return; - } + { + // Evaluate if we need to skip this message when that setting is true (default is false) + skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... + skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself + } + + bool new_session = !hasSession(new_session_id); + if (new_session) + { + // Group chat session was initiated by muted resident, do not start this session viewerside + // do not send leave msg either, so we are able to get group messages from other participants + if ((IM_SESSION_INVITE == dialog) && gAgent.isInGroup(new_session_id) && + LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + return; + } + + LLAvatarName av_name; + if (LLAvatarNameCache::get(other_participant_id, &av_name) && !name_is_setted) + { + fixed_session_name = av_name.getDisplayName(); + } + LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); + + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); + if (session) + { + skip_message &= !session->isGroupSessionType(); // Do not skip group chats... + if (skip_message) + { + gIMMgr->leaveSession(new_session_id); + } + // When we get a new IM, and if you are a god, display a bit + // of information about the source. This is to help liaisons + // when answering questions. + if (gAgent.isGodlike()) + { + // *TODO:translate (low priority, god ability) + std::ostringstream bonus_info; + bonus_info << LLTrans::getString("***") + " " + LLTrans::getString("IMParentEstate") + ":" + " " + << parent_estate_id + << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") + << ((parent_estate_id == 5) ? "," + LLTrans::getString("IMTeen") : ""); + + // once we have web-services (or something) which returns + // information about a region id, we can print this out + // and even have it link to map-teleport or something. + //<< "*** region_id: " << region_id << std::endl + //<< "*** position: " << position << std::endl; + + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str(), true, is_region_msg); + } + + // Logically it would make more sense to reject the session sooner, in another area of the + // code, but the session has to be established inside the server before it can be left. + if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; + if (!gIMMgr->leaveSession(new_session_id)) + { + LL_INFOS("IMVIEW") << "Session " << new_session_id << " does not exist." << LL_ENDL; + } + return; + } // Fetch group chat history, enabled by default. if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) @@ -3169,131 +3169,131 @@ void LLIMMgr::addMessage( } } - //Play sound for new conversations - if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } - } - else - { - // Failed to create a session, most likely due to empty name (name cache failed?) - LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL; - } - } - - if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) - { - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp); - } - - // Open conversation floater if offline messages are present - if (is_offline_msg && !skip_message) + //Play sound for new conversations + if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else + { + // Failed to create a session, most likely due to empty name (name cache failed?) + LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL; + } + } + + if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) + { + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp); + } + + // Open conversation floater if offline messages are present + if (is_offline_msg && !skip_message) { LLFloaterReg::showInstance("im_container"); - LLFloaterReg::getTypedInstance("im_container")-> - flashConversationItemWidget(new_session_id, true); + LLFloaterReg::getTypedInstance("im_container")-> + flashConversationItemWidget(new_session_id, true); } } void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args) { - LLUIString message; - - // null session id means near me (chat history) - if (session_id.isNull()) - { - message = LLTrans::getString(message_name); - message.setArgs(args); - - LLChat chat(message); - chat.mSourceType = CHAT_SOURCE_SYSTEM; - - LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance("nearby_chat"); - if (nearby_chat) - { - nearby_chat->addMessage(chat); - } - } - else // going to IM session - { - message = LLTrans::getString(message_name + "-im"); - message.setArgs(args); - if (hasSession(session_id)) - { - gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); - } - // log message to file - - else - { - LLAvatarName av_name; - // since we select user to share item with - his name is already in cache - LLAvatarNameCache::get(args["user_id"], &av_name); - std::string session_name = LLCacheName::buildUsername(av_name.getUserName()); - LLIMModel::instance().logToFile(session_name, SYSTEM_FROM, LLUUID::null, message.getString()); - } - } + LLUIString message; + + // null session id means near me (chat history) + if (session_id.isNull()) + { + message = LLTrans::getString(message_name); + message.setArgs(args); + + LLChat chat(message); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance("nearby_chat"); + if (nearby_chat) + { + nearby_chat->addMessage(chat); + } + } + else // going to IM session + { + message = LLTrans::getString(message_name + "-im"); + message.setArgs(args); + if (hasSession(session_id)) + { + gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); + } + // log message to file + + else + { + LLAvatarName av_name; + // since we select user to share item with - his name is already in cache + LLAvatarNameCache::get(args["user_id"], &av_name); + std::string session_name = LLCacheName::buildUsername(av_name.getUserName()); + LLIMModel::instance().logToFile(session_name, SYSTEM_FROM, LLUUID::null, message.getString()); + } + } } S32 LLIMMgr::getNumberOfUnreadIM() { - std::map::iterator it; + std::map::iterator it; - S32 num = 0; - for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - num += (*it).second->mNumUnread; - } + S32 num = 0; + for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + num += (*it).second->mNumUnread; + } - return num; + return num; } S32 LLIMMgr::getNumberOfUnreadParticipantMessages() { - std::map::iterator it; + std::map::iterator it; - S32 num = 0; - for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - num += (*it).second->mParticipantUnreadMessageCount; - } + S32 num = 0; + for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + num += (*it).second->mParticipantUnreadMessageCount; + } - return num; + return num; } void LLIMMgr::autoStartCallOnStartup(const LLUUID& session_id) { - LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id); - if (!session) return; + LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id); + if (!session) return; - if (session->mSessionInitialized) - { - startCall(session_id); - } - else - { - session->mStartCallOnInitialize = true; - } + if (session->mSessionInitialized) + { + startCall(session_id); + } + else + { + session->mStartCallOnInitialize = true; + } } LLUUID LLIMMgr::addP2PSession(const std::string& name, - const LLUUID& other_participant_id, - const std::string& voice_session_handle, - const std::string& caller_uri) + const LLUUID& other_participant_id, + const std::string& voice_session_handle, + const std::string& caller_uri) { - LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id, true); + LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id, true); - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - LLVoiceChannelP2P* voice_channel = dynamic_cast(speaker_mgr->getVoiceChannel()); - if (voice_channel) - { - voice_channel->setSessionHandle(voice_session_handle, caller_uri); - } - } - return session_id; + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + LLVoiceChannelP2P* voice_channel = dynamic_cast(speaker_mgr->getVoiceChannel()); + if (voice_channel) + { + voice_channel->setSessionHandle(voice_session_handle, caller_uri); + } + } + return session_id; } // This adds a session to the talk view. The name is the local name of @@ -3301,70 +3301,70 @@ LLUUID LLIMMgr::addP2PSession(const std::string& name, // exists, it is brought forward. Specifying id = NULL results in an // im session to everyone. Returns the uuid of the session. LLUUID LLIMMgr::addSession( - const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, bool voice) + const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, bool voice) { - std::vector ids; - ids.push_back(other_participant_id); - LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice); - return session_id; + std::vector ids; + ids.push_back(other_participant_id); + LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice); + return session_id; } // Adds a session using the given session_id. If the session already exists // the dialog type is assumed correct. Returns the uuid of the session. LLUUID LLIMMgr::addSession( - const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, - const std::vector& ids, bool voice, - const LLUUID& floater_id) -{ - if (ids.empty()) - { - return LLUUID::null; - } - - if (name.empty()) - { - LL_WARNS() << "Session name cannot be null!" << LL_ENDL; - return LLUUID::null; - } - - LLUUID session_id = computeSessionID(dialog,other_participant_id); - - if (floater_id.notNull()) - { - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(floater_id); - - if (im_floater) - { - // The IM floater should be initialized with a new session_id - // so that it is found by that id when creating a chiclet in LLFloaterIMSession::onIMChicletCreated, - // and a new floater is not created. - im_floater->initIMSession(session_id); + const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, + const std::vector& ids, bool voice, + const LLUUID& floater_id) +{ + if (ids.empty()) + { + return LLUUID::null; + } + + if (name.empty()) + { + LL_WARNS() << "Session name cannot be null!" << LL_ENDL; + return LLUUID::null; + } + + LLUUID session_id = computeSessionID(dialog,other_participant_id); + + if (floater_id.notNull()) + { + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(floater_id); + + if (im_floater) + { + // The IM floater should be initialized with a new session_id + // so that it is found by that id when creating a chiclet in LLFloaterIMSession::onIMChicletCreated, + // and a new floater is not created. + im_floater->initIMSession(session_id); im_floater->reloadMessages(); - } - } - - bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); - - //works only for outgoing ad-hoc sessions - if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) - { - LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids); - if (ad_hoc_found) - { - new_session = false; - session_id = ad_hoc_found->mSessionID; - } - } + } + } + + bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); + + //works only for outgoing ad-hoc sessions + if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) + { + LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids); + if (ad_hoc_found) + { + new_session = false; + session_id = ad_hoc_found->mSessionID; + } + } //Notify observers that a session was added - if (new_session) - { - LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice); - } + if (new_session) + { + LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice); + } //Notifies observers that the session was already added else { @@ -3372,334 +3372,334 @@ LLUUID LLIMMgr::addSession( LLIMMgr::getInstance()->notifyObserverSessionActivated(session_id, session_name, other_participant_id); } - //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions - if (!new_session) return session_id; + //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions + if (!new_session) return session_id; LL_INFOS("IMVIEW") << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << LL_ENDL; - //Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609) - //*TODO After February 2010 remove this commented out line if no one will be missing that warning - //noteOfflineUsers(session_id, floater, ids); + //Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609) + //*TODO After February 2010 remove this commented out line if no one will be missing that warning + //noteOfflineUsers(session_id, floater, ids); - // Only warn for regular IMs - not group IMs - if( dialog == IM_NOTHING_SPECIAL ) - { - noteMutedUsers(session_id, ids); - } + // Only warn for regular IMs - not group IMs + if( dialog == IM_NOTHING_SPECIAL ) + { + noteMutedUsers(session_id, ids); + } - notifyObserverSessionVoiceOrIMStarted(session_id); + notifyObserverSessionVoiceOrIMStarted(session_id); - return session_id; + return session_id; } bool LLIMMgr::leaveSession(const LLUUID& session_id) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; - LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID); - gIMMgr->removeSession(session_id); - return true; + LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID); + gIMMgr->removeSession(session_id); + return true; } // Removes data associated with a particular session specified by session_id void LLIMMgr::removeSession(const LLUUID& session_id) { - llassert_always(hasSession(session_id)); + llassert_always(hasSession(session_id)); - clearPendingInvitation(session_id); - clearPendingAgentListUpdates(session_id); + clearPendingInvitation(session_id); + clearPendingAgentListUpdates(session_id); - LLIMModel::getInstance()->clearSession(session_id); + LLIMModel::getInstance()->clearSession(session_id); LL_INFOS("IMVIEW") << "LLIMMgr::removeSession, session removed, session id = " << session_id << LL_ENDL; - notifyObserverSessionRemoved(session_id); + notifyObserverSessionRemoved(session_id); } void LLIMMgr::inviteToSession( - const LLUUID& session_id, - const std::string& session_name, - const LLUUID& caller_id, - const std::string& caller_name, - EInstantMessage type, - EInvitationType inv_type, - const std::string& session_handle, - const std::string& session_uri) -{ - std::string notify_box_type; - // voice invite question is different from default only for group call (EXT-7118) - std::string question_type = "VoiceInviteQuestionDefault"; - - BOOL voice_invite = FALSE; - bool is_linden = LLMuteList::isLinden(caller_name); - - - if(type == IM_SESSION_P2P_INVITE) - { - //P2P is different...they only have voice invitations - notify_box_type = "VoiceInviteP2P"; - voice_invite = TRUE; - } - else if ( gAgent.isInGroup(session_id, TRUE) ) - { - //only really old school groups have voice invitations - notify_box_type = "VoiceInviteGroup"; - question_type = "VoiceInviteQuestionGroup"; - voice_invite = TRUE; - } - else if ( inv_type == INVITATION_TYPE_VOICE ) - { - //else it's an ad-hoc - //and a voice ad-hoc - notify_box_type = "VoiceInviteAdHoc"; - voice_invite = TRUE; - } - else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) - { - notify_box_type = "InviteAdHoc"; - } - - LLSD payload; - payload["session_id"] = session_id; - payload["session_name"] = session_name; - payload["caller_id"] = caller_id; - payload["caller_name"] = caller_name; - payload["type"] = type; - payload["inv_type"] = inv_type; - payload["session_handle"] = session_handle; - payload["session_uri"] = session_uri; - payload["notify_box_type"] = notify_box_type; - payload["question_type"] = question_type; - - //ignore invites from muted residents - if (!is_linden) - { - if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagVoiceChat) - && voice_invite && "VoiceInviteQuestionDefault" == question_type) - { - LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; - LLIncomingCallDialog::processCallResponse(1, payload); - return; - } - else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite) - { - LL_INFOS("IMVIEW") << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; - return; - } - } - - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); - if (channelp && channelp->callStarted()) - { - // you have already started a call to the other user, so just accept the invite - LLIncomingCallDialog::processCallResponse(0, payload); - return; - } - - if (voice_invite) - { - bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup")); + const LLUUID& session_id, + const std::string& session_name, + const LLUUID& caller_id, + const std::string& caller_name, + EInstantMessage type, + EInvitationType inv_type, + const std::string& session_handle, + const std::string& session_uri) +{ + std::string notify_box_type; + // voice invite question is different from default only for group call (EXT-7118) + std::string question_type = "VoiceInviteQuestionDefault"; + + BOOL voice_invite = FALSE; + bool is_linden = LLMuteList::isLinden(caller_name); + + + if(type == IM_SESSION_P2P_INVITE) + { + //P2P is different...they only have voice invitations + notify_box_type = "VoiceInviteP2P"; + voice_invite = TRUE; + } + else if ( gAgent.isInGroup(session_id, TRUE) ) + { + //only really old school groups have voice invitations + notify_box_type = "VoiceInviteGroup"; + question_type = "VoiceInviteQuestionGroup"; + voice_invite = TRUE; + } + else if ( inv_type == INVITATION_TYPE_VOICE ) + { + //else it's an ad-hoc + //and a voice ad-hoc + notify_box_type = "VoiceInviteAdHoc"; + voice_invite = TRUE; + } + else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) + { + notify_box_type = "InviteAdHoc"; + } + + LLSD payload; + payload["session_id"] = session_id; + payload["session_name"] = session_name; + payload["caller_id"] = caller_id; + payload["caller_name"] = caller_name; + payload["type"] = type; + payload["inv_type"] = inv_type; + payload["session_handle"] = session_handle; + payload["session_uri"] = session_uri; + payload["notify_box_type"] = notify_box_type; + payload["question_type"] = question_type; + + //ignore invites from muted residents + if (!is_linden) + { + if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagVoiceChat) + && voice_invite && "VoiceInviteQuestionDefault" == question_type) + { + LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; + LLIncomingCallDialog::processCallResponse(1, payload); + return; + } + else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite) + { + LL_INFOS("IMVIEW") << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; + return; + } + } + + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); + if (channelp && channelp->callStarted()) + { + // you have already started a call to the other user, so just accept the invite + LLIncomingCallDialog::processCallResponse(0, payload); + return; + } + + if (voice_invite) + { + bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup")); bool isRejectNonFriendCall = (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)); - if (isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb()) - { - if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall) - { - if (!hasSession(session_id) && (type == IM_SESSION_P2P_INVITE)) - { - std::string fixed_session_name = caller_name; - if(!session_name.empty() && session_name.size()>1) - { - fixed_session_name = session_name; - } - else - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(caller_id, &av_name)) - { - fixed_session_name = av_name.getDisplayName(); - } - } - LLIMModel::getInstance()->newSession(session_id, fixed_session_name, IM_NOTHING_SPECIAL, caller_id, false, false); - } - - LLSD args; - addSystemMessage(session_id, "you_auto_rejected_call", args); - send_do_not_disturb_message(gMessageSystem, caller_id, session_id); - } - // silently decline the call - LLIncomingCallDialog::processCallResponse(1, payload); - return; - } - } - - if ( !mPendingInvitations.has(session_id.asString()) ) - { - if (caller_name.empty()) - { - LLAvatarNameCache::get(caller_id, - boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2)); - } - else - { - LLFloaterReg::showInstance("incoming_call", payload, FALSE); - } - - // Add the caller to the Recent List here (at this point - // "incoming_call" floater is shown and the recipient can - // reject the call), because even if a recipient will reject - // the call, the caller should be added to the recent list - // anyway. STORM-507. - if(type == IM_SESSION_P2P_INVITE) - LLRecentPeople::instance().add(caller_id); - - mPendingInvitations[session_id.asString()] = LLSD(); - } + if (isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb()) + { + if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall) + { + if (!hasSession(session_id) && (type == IM_SESSION_P2P_INVITE)) + { + std::string fixed_session_name = caller_name; + if(!session_name.empty() && session_name.size()>1) + { + fixed_session_name = session_name; + } + else + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(caller_id, &av_name)) + { + fixed_session_name = av_name.getDisplayName(); + } + } + LLIMModel::getInstance()->newSession(session_id, fixed_session_name, IM_NOTHING_SPECIAL, caller_id, false, false); + } + + LLSD args; + addSystemMessage(session_id, "you_auto_rejected_call", args); + send_do_not_disturb_message(gMessageSystem, caller_id, session_id); + } + // silently decline the call + LLIncomingCallDialog::processCallResponse(1, payload); + return; + } + } + + if ( !mPendingInvitations.has(session_id.asString()) ) + { + if (caller_name.empty()) + { + LLAvatarNameCache::get(caller_id, + boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2)); + } + else + { + LLFloaterReg::showInstance("incoming_call", payload, FALSE); + } + + // Add the caller to the Recent List here (at this point + // "incoming_call" floater is shown and the recipient can + // reject the call), because even if a recipient will reject + // the call, the caller should be added to the recent list + // anyway. STORM-507. + if(type == IM_SESSION_P2P_INVITE) + LLRecentPeople::instance().add(caller_id); + + mPendingInvitations[session_id.asString()] = LLSD(); + } } void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const LLAvatarName& av_name) { - payload["caller_name"] = av_name.getUserName(); - payload["session_name"] = payload["caller_name"].asString(); + payload["caller_name"] = av_name.getUserName(); + payload["session_name"] = payload["caller_name"].asString(); - std::string notify_box_type = payload["notify_box_type"].asString(); + std::string notify_box_type = payload["notify_box_type"].asString(); - LLFloaterReg::showInstance("incoming_call", payload, FALSE); + LLFloaterReg::showInstance("incoming_call", payload, FALSE); } //*TODO disconnects all sessions void LLIMMgr::disconnectAllSessions() { - //*TODO disconnects all IM sessions + //*TODO disconnects all IM sessions } BOOL LLIMMgr::hasSession(const LLUUID& session_id) { - return LLIMModel::getInstance()->findIMSession(session_id) != NULL; + return LLIMModel::getInstance()->findIMSession(session_id) != NULL; } void LLIMMgr::clearPendingInvitation(const LLUUID& session_id) { - if ( mPendingInvitations.has(session_id.asString()) ) - { - mPendingInvitations.erase(session_id.asString()); - } + if ( mPendingInvitations.has(session_id.asString()) ) + { + mPendingInvitations.erase(session_id.asString()); + } } void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body) { - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - im_floater->processAgentListUpdates(body); - } - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - speaker_mgr->updateSpeakers(body); - - // also the same call is added into LLVoiceClient::participantUpdatedEvent because - // sometimes it is called AFTER LLViewerChatterBoxSessionAgentListUpdates::post() - // when moderation state changed too late. See EXT-3544. - speaker_mgr->update(true); - } - else - { - //we don't have a speaker manager yet..something went wrong - //we are probably receiving an update here before - //a start or an acceptance of an invitation. Race condition. - gIMMgr->addPendingAgentListUpdates( - session_id, - body); - } + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + im_floater->processAgentListUpdates(body); + } + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->updateSpeakers(body); + + // also the same call is added into LLVoiceClient::participantUpdatedEvent because + // sometimes it is called AFTER LLViewerChatterBoxSessionAgentListUpdates::post() + // when moderation state changed too late. See EXT-3544. + speaker_mgr->update(true); + } + else + { + //we don't have a speaker manager yet..something went wrong + //we are probably receiving an update here before + //a start or an acceptance of an invitation. Race condition. + gIMMgr->addPendingAgentListUpdates( + session_id, + body); + } } LLSD LLIMMgr::getPendingAgentListUpdates(const LLUUID& session_id) { - if ( mPendingAgentListUpdates.has(session_id.asString()) ) - { - return mPendingAgentListUpdates[session_id.asString()]; - } - else - { - return LLSD(); - } + if ( mPendingAgentListUpdates.has(session_id.asString()) ) + { + return mPendingAgentListUpdates[session_id.asString()]; + } + else + { + return LLSD(); + } } void LLIMMgr::addPendingAgentListUpdates( - const LLUUID& session_id, - const LLSD& updates) -{ - LLSD::map_const_iterator iter; - - if ( !mPendingAgentListUpdates.has(session_id.asString()) ) - { - //this is a new agent list update for this session - mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap(); - } - - if ( - updates.has("agent_updates") && - updates["agent_updates"].isMap() && - updates.has("updates") && - updates["updates"].isMap() ) - { - //new school update - LLSD update_types = LLSD::emptyArray(); - LLSD::array_iterator array_iter; - - update_types.append("agent_updates"); - update_types.append("updates"); - - for ( - array_iter = update_types.beginArray(); - array_iter != update_types.endArray(); - ++array_iter) - { - //we only want to include the last update for a given agent - for ( - iter = updates[array_iter->asString()].beginMap(); - iter != updates[array_iter->asString()].endMap(); - ++iter) - { - mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] = - iter->second; - } - } - } - else if ( - updates.has("updates") && - updates["updates"].isMap() ) - { - //old school update where the SD contained just mappings - //of agent_id -> "LEAVE"/"ENTER" - - //only want to keep last update for each agent - for ( - iter = updates["updates"].beginMap(); - iter != updates["updates"].endMap(); - ++iter) - { - mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] = - iter->second; - } - } + const LLUUID& session_id, + const LLSD& updates) +{ + LLSD::map_const_iterator iter; + + if ( !mPendingAgentListUpdates.has(session_id.asString()) ) + { + //this is a new agent list update for this session + mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap(); + } + + if ( + updates.has("agent_updates") && + updates["agent_updates"].isMap() && + updates.has("updates") && + updates["updates"].isMap() ) + { + //new school update + LLSD update_types = LLSD::emptyArray(); + LLSD::array_iterator array_iter; + + update_types.append("agent_updates"); + update_types.append("updates"); + + for ( + array_iter = update_types.beginArray(); + array_iter != update_types.endArray(); + ++array_iter) + { + //we only want to include the last update for a given agent + for ( + iter = updates[array_iter->asString()].beginMap(); + iter != updates[array_iter->asString()].endMap(); + ++iter) + { + mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] = + iter->second; + } + } + } + else if ( + updates.has("updates") && + updates["updates"].isMap() ) + { + //old school update where the SD contained just mappings + //of agent_id -> "LEAVE"/"ENTER" + + //only want to keep last update for each agent + for ( + iter = updates["updates"].beginMap(); + iter != updates["updates"].endMap(); + ++iter) + { + mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] = + iter->second; + } + } } void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id) { - if ( mPendingAgentListUpdates.has(session_id.asString()) ) - { - mPendingAgentListUpdates.erase(session_id.asString()); - } + if ( mPendingAgentListUpdates.has(session_id.asString()) ) + { + mPendingAgentListUpdates.erase(session_id.asString()); + } } void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionAdded(session_id, name, other_participant_id, has_offline_msg); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionAdded(session_id, name, other_participant_id, has_offline_msg); + } } void LLIMMgr::notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) @@ -3712,239 +3712,239 @@ void LLIMMgr::notifyObserverSessionActivated(const LLUUID& session_id, const std void LLIMMgr::notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionVoiceOrIMStarted(session_id); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionVoiceOrIMStarted(session_id); + } } void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionRemoved(session_id); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionRemoved(session_id); + } } void LLIMMgr::notifyObserverSessionIDUpdated( const LLUUID& old_session_id, const LLUUID& new_session_id ) { - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionIDUpdated(old_session_id, new_session_id); - } + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionIDUpdated(old_session_id, new_session_id); + } } void LLIMMgr::addSessionObserver(LLIMSessionObserver *observer) { - mSessionObservers.push_back(observer); + mSessionObservers.push_back(observer); } void LLIMMgr::removeSessionObserver(LLIMSessionObserver *observer) { - mSessionObservers.remove(observer); + mSessionObservers.remove(observer); } bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection direction) { - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); - if (!voice_channel) return false; + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); + if (!voice_channel) return false; - voice_channel->setCallDirection(direction); - voice_channel->activate(); - return true; + voice_channel->setCallDirection(direction); + voice_channel->activate(); + return true; } bool LLIMMgr::endCall(const LLUUID& session_id) { - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); - if (!voice_channel) return false; + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); + if (!voice_channel) return false; - voice_channel->deactivate(); - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (im_session) - { - // need to update speakers' state - im_session->mSpeakers->update(FALSE); - } - return true; + voice_channel->deactivate(); + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (im_session) + { + // need to update speakers' state + im_session->mSpeakers->update(FALSE); + } + return true; } bool LLIMMgr::isVoiceCall(const LLUUID& session_id) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; - return im_session->mStartedAsIMCall; + return im_session->mStartedAsIMCall; } void LLIMMgr::updateDNDMessageStatus() { - if (LLIMModel::getInstance()->mId2SessionMap.empty()) return; + if (LLIMModel::getInstance()->mId2SessionMap.empty()) return; - std::map::const_iterator it = LLIMModel::getInstance()->mId2SessionMap.begin(); - for (; it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - LLIMModel::LLIMSession* session = (*it).second; + std::map::const_iterator it = LLIMModel::getInstance()->mId2SessionMap.begin(); + for (; it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + LLIMModel::LLIMSession* session = (*it).second; - if (session->isP2P()) - { - setDNDMessageSent(session->mSessionID,false); - } - } + if (session->isP2P()) + { + setDNDMessageSent(session->mSessionID,false); + } + } } bool LLIMMgr::isDNDMessageSend(const LLUUID& session_id) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; - return im_session->mIsDNDsend; + return im_session->mIsDNDsend; } void LLIMMgr::setDNDMessageSent(const LLUUID& session_id, bool is_send) { - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return; + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return; - im_session->mIsDNDsend = is_send; + im_session->mIsDNDsend = is_send; } void LLIMMgr::addNotifiedNonFriendSessionID(const LLUUID& session_id) { - mNotifiedNonFriendSessions.insert(session_id); + mNotifiedNonFriendSessions.insert(session_id); } bool LLIMMgr::isNonFriendSessionNotified(const LLUUID& session_id) { - return mNotifiedNonFriendSessions.end() != mNotifiedNonFriendSessions.find(session_id); + return mNotifiedNonFriendSessions.end() != mNotifiedNonFriendSessions.find(session_id); } void LLIMMgr::noteOfflineUsers( - const LLUUID& session_id, - const std::vector& ids) -{ - S32 count = ids.size(); - if(count == 0) - { - const std::string& only_user = LLTrans::getString("only_user_message"); - LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, only_user); - } - else - { - const LLRelationship* info = NULL; - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLIMModel& im_model = LLIMModel::instance(); - for(S32 i = 0; i < count; ++i) - { - info = at.getBuddyInfo(ids.at(i)); - LLAvatarName av_name; - if (info - && !info->isOnline() - && LLAvatarNameCache::get(ids.at(i), &av_name)) - { - LLUIString offline = LLTrans::getString("offline_message"); - // Use display name only because this user is your friend - offline.setArg("[NAME]", av_name.getDisplayName()); - im_model.proccessOnlineOfflineNotification(session_id, offline); - } - } - } + const LLUUID& session_id, + const std::vector& ids) +{ + S32 count = ids.size(); + if(count == 0) + { + const std::string& only_user = LLTrans::getString("only_user_message"); + LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, only_user); + } + else + { + const LLRelationship* info = NULL; + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLIMModel& im_model = LLIMModel::instance(); + for(S32 i = 0; i < count; ++i) + { + info = at.getBuddyInfo(ids.at(i)); + LLAvatarName av_name; + if (info + && !info->isOnline() + && LLAvatarNameCache::get(ids.at(i), &av_name)) + { + LLUIString offline = LLTrans::getString("offline_message"); + // Use display name only because this user is your friend + offline.setArg("[NAME]", av_name.getDisplayName()); + im_model.proccessOnlineOfflineNotification(session_id, offline); + } + } + } } void LLIMMgr::noteMutedUsers(const LLUUID& session_id, - const std::vector& ids) + const std::vector& ids) { - // Don't do this if we don't have a mute list. - LLMuteList *ml = LLMuteList::getInstance(); - if( !ml ) - { - return; - } + // Don't do this if we don't have a mute list. + LLMuteList *ml = LLMuteList::getInstance(); + if( !ml ) + { + return; + } - S32 count = ids.size(); - if(count > 0) - { - LLIMModel* im_model = LLIMModel::getInstance(); + S32 count = ids.size(); + if(count > 0) + { + LLIMModel* im_model = LLIMModel::getInstance(); - for(S32 i = 0; i < count; ++i) - { - if( ml->isMuted(ids.at(i)) ) - { - LLUIString muted = LLTrans::getString("muted_message"); + for(S32 i = 0; i < count; ++i) + { + if( ml->isMuted(ids.at(i)) ) + { + LLUIString muted = LLTrans::getString("muted_message"); - im_model->addMessage(session_id, SYSTEM_FROM, LLUUID::null, muted); - break; - } - } - } + im_model->addMessage(session_id, SYSTEM_FROM, LLUUID::null, muted); + break; + } + } + } } void LLIMMgr::processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(from_id, im_type, TRUE); + processIMTypingCore(from_id, im_type, TRUE); } void LLIMMgr::processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(from_id, im_type, FALSE); + processIMTypingCore(from_id, im_type, FALSE); } void LLIMMgr::processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing) { - LLUUID session_id = computeSessionID(im_type, from_id); - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - im_floater->processIMTyping(from_id, typing); - } + LLUUID session_id = computeSessionID(im_type, from_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + im_floater->processIMTyping(from_id, typing); + } } class LLViewerChatterBoxSessionStartReply : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); - desc.postAPI(); - desc.input( - "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLSD body; - LLUUID temp_session_id; - LLUUID session_id; - bool success; - - body = input["body"]; - success = body["success"].asBoolean(); - temp_session_id = body["temp_session_id"].asUUID(); - - if ( success ) - { - session_id = body["session_id"].asUUID(); - - LLIMModel::getInstance()->processSessionInitializedReply(temp_session_id, session_id); - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - speaker_mgr->setSpeakers(body); - speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); - } - - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - if ( body.has("session_info") ) - { - im_floater->processSessionUpdate(body["session_info"]); + virtual void describe(Description& desc) const + { + desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); + desc.postAPI(); + desc.input( + "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string"); + desc.source(__FILE__, __LINE__); + } + + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLSD body; + LLUUID temp_session_id; + LLUUID session_id; + bool success; + + body = input["body"]; + success = body["success"].asBoolean(); + temp_session_id = body["temp_session_id"].asUUID(); + + if ( success ) + { + session_id = body["session_id"].asUUID(); + + LLIMModel::getInstance()->processSessionInitializedReply(temp_session_id, session_id); + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->setSpeakers(body); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); + } + + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + if ( body.has("session_info") ) + { + im_floater->processSessionUpdate(body["session_info"]); // Send request for chat history, if enabled. if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) @@ -3954,104 +3954,104 @@ public: boost::bind(&chatterBoxHistoryCoro, url, session_id, "", "", 0)); } } - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - } - else - { - //throw an error dialog and close the temp session's floater - gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id); - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + } + else + { + //throw an error dialog and close the temp session's floater + gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id); + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + } }; class LLViewerChatterBoxSessionEventReply : public LLHTTPNode { public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); - desc.postAPI(); - desc.input( - "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id; - bool success; - - LLSD body = input["body"]; - success = body["success"].asBoolean(); - session_id = body["session_id"].asUUID(); - - if ( !success ) - { - //throw an error dialog - gIMMgr->showSessionEventError( - body["event"].asString(), - body["error"].asString(), - session_id); - } - } + virtual void describe(Description& desc) const + { + desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); + desc.postAPI(); + desc.input( + "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID"); + desc.source(__FILE__, __LINE__); + } + + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id; + bool success; + + LLSD body = input["body"]; + success = body["success"].asBoolean(); + session_id = body["session_id"].asUUID(); + + if ( !success ) + { + //throw an error dialog + gIMMgr->showSessionEventError( + body["event"].asString(), + body["error"].asString(), + session_id); + } + } }; class LLViewerForceCloseChatterBoxSession: public LLHTTPNode { public: - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id; - std::string reason; - - session_id = input["body"]["session_id"].asUUID(); - reason = input["body"]["reason"].asString(); - - gIMMgr->showSessionForceClose(reason, session_id); - } + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id; + std::string reason; + + session_id = input["body"]["session_id"].asUUID(); + reason = input["body"]["reason"].asString(); + + gIMMgr->showSessionForceClose(reason, session_id); + } }; class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode { public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - const LLUUID& session_id = input["body"]["session_id"].asUUID(); - gIMMgr->processAgentListUpdates(session_id, input["body"]); - } + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + const LLUUID& session_id = input["body"]["session_id"].asUUID(); + gIMMgr->processAgentListUpdates(session_id, input["body"]); + } }; class LLViewerChatterBoxSessionUpdate : public LLHTTPNode { public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id = input["body"]["session_id"].asUUID(); - LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); - if ( im_floater ) - { - im_floater->processSessionUpdate(input["body"]["info"]); - } - LLIMSpeakerMgr* im_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (im_mgr) - { - im_mgr->processSessionUpdate(input["body"]["info"]); - } - } + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id = input["body"]["session_id"].asUUID(); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); + if ( im_floater ) + { + im_floater->processSessionUpdate(input["body"]["info"]); + } + LLIMSpeakerMgr* im_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (im_mgr) + { + im_mgr->processSessionUpdate(input["body"]["info"]); + } + } }; @@ -4059,135 +4059,135 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode { public: - virtual void post( - ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - //for backwards compatiblity reasons...we need to still - //check for 'text' or 'voice' invitations...bleh - if ( input["body"].has("instantmessage") ) - { - LLSD message_params = - input["body"]["instantmessage"]["message_params"]; - - //do something here to have the IM invite behave - //just like a normal IM - //this is just replicated code from process_improved_im - //and should really go in it's own function -jwolk - - std::string message = message_params["message"].asString(); - std::string name = message_params["from_name"].asString(); - LLUUID from_id = message_params["from_id"].asUUID(); - LLUUID session_id = message_params["id"].asUUID(); - std::vector bin_bucket = message_params["data"]["binary_bucket"].asBinary(); - U8 offline = (U8)message_params["offline"].asInteger(); - - time_t timestamp = - (time_t) message_params["timestamp"].asInteger(); - - BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - - //don't return if user is muted b/c proper way to ignore a muted user who - //initiated an adhoc/group conference is to create then leave the session (see STORM-1731) - if (is_do_not_disturb) - { - return; - } - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - std::string buffer = saved + message; - - if(from_id == gAgentID) - { - return; - } - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - IM_OFFLINE == offline, - std::string((char*)&bin_bucket[0]), - IM_SESSION_INVITE, - message_params["parent_estate_id"].asInteger(), - message_params["region_id"].asUUID(), - ll_vector3_from_sd(message_params["position"]), + virtual void post( + ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + //for backwards compatiblity reasons...we need to still + //check for 'text' or 'voice' invitations...bleh + if ( input["body"].has("instantmessage") ) + { + LLSD message_params = + input["body"]["instantmessage"]["message_params"]; + + //do something here to have the IM invite behave + //just like a normal IM + //this is just replicated code from process_improved_im + //and should really go in it's own function -jwolk + + std::string message = message_params["message"].asString(); + std::string name = message_params["from_name"].asString(); + LLUUID from_id = message_params["from_id"].asUUID(); + LLUUID session_id = message_params["id"].asUUID(); + std::vector bin_bucket = message_params["data"]["binary_bucket"].asBinary(); + U8 offline = (U8)message_params["offline"].asInteger(); + + time_t timestamp = + (time_t) message_params["timestamp"].asInteger(); + + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); + + //don't return if user is muted b/c proper way to ignore a muted user who + //initiated an adhoc/group conference is to create then leave the session (see STORM-1731) + if (is_do_not_disturb) + { + return; + } + + // standard message, not from system + std::string saved; + if(offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + std::string buffer = saved + message; + + if(from_id == gAgentID) + { + return; + } + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + IM_OFFLINE == offline, + std::string((char*)&bin_bucket[0]), + IM_SESSION_INVITE, + message_params["parent_estate_id"].asInteger(), + message_params["region_id"].asUUID(), + ll_vector3_from_sd(message_params["position"]), false, // is_region_message timestamp); - if (LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat)) - { - return; - } + if (LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat)) + { + return; + } - //K now we want to accept the invitation - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + //K now we want to accept the invitation + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - if ( url != "" ) - { + if ( url != "" ) + { LLCoros::instance().launch("chatterBoxInvitationCoro", boost::bind(&chatterBoxInvitationCoro, url, session_id, LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); - } - } //end if invitation has instant message - else if ( input["body"].has("voice") ) - { - if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking()) - { - // Don't display voice invites unless the user has voice enabled. - return; - } - - gIMMgr->inviteToSession( - input["body"]["session_id"].asUUID(), - input["body"]["session_name"].asString(), - input["body"]["from_id"].asUUID(), - input["body"]["from_name"].asString(), - IM_SESSION_INVITE, - LLIMMgr::INVITATION_TYPE_VOICE); - } - else if ( input["body"].has("immediate") ) - { - gIMMgr->inviteToSession( - input["body"]["session_id"].asUUID(), - input["body"]["session_name"].asString(), - input["body"]["from_id"].asUUID(), - input["body"]["from_name"].asString(), - IM_SESSION_INVITE, - LLIMMgr::INVITATION_TYPE_IMMEDIATE); - } - } + } + } //end if invitation has instant message + else if ( input["body"].has("voice") ) + { + if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking()) + { + // Don't display voice invites unless the user has voice enabled. + return; + } + + gIMMgr->inviteToSession( + input["body"]["session_id"].asUUID(), + input["body"]["session_name"].asString(), + input["body"]["from_id"].asUUID(), + input["body"]["from_name"].asString(), + IM_SESSION_INVITE, + LLIMMgr::INVITATION_TYPE_VOICE); + } + else if ( input["body"].has("immediate") ) + { + gIMMgr->inviteToSession( + input["body"]["session_id"].asUUID(), + input["body"]["session_name"].asString(), + input["body"]["from_id"].asUUID(), + input["body"]["from_name"].asString(), + IM_SESSION_INVITE, + LLIMMgr::INVITATION_TYPE_IMMEDIATE); + } + } }; LLHTTPRegistration gHTTPRegistrationMessageChatterboxsessionstartreply( - "/message/ChatterBoxSessionStartReply"); + "/message/ChatterBoxSessionStartReply"); LLHTTPRegistration gHTTPRegistrationMessageChatterboxsessioneventreply( - "/message/ChatterBoxSessionEventReply"); + "/message/ChatterBoxSessionEventReply"); LLHTTPRegistration gHTTPRegistrationMessageForceclosechatterboxsession( - "/message/ForceCloseChatterBoxSession"); + "/message/ForceCloseChatterBoxSession"); LLHTTPRegistration gHTTPRegistrationMessageChatterboxsessionagentlistupdates( - "/message/ChatterBoxSessionAgentListUpdates"); + "/message/ChatterBoxSessionAgentListUpdates"); LLHTTPRegistration gHTTPRegistrationMessageChatterBoxSessionUpdate( - "/message/ChatterBoxSessionUpdate"); + "/message/ChatterBoxSessionUpdate"); LLHTTPRegistration gHTTPRegistrationMessageChatterBoxInvitation( - "/message/ChatterBoxInvitation"); + "/message/ChatterBoxInvitation"); diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index f0e3e26a86..a8c1f28ad5 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -1,25 +1,25 @@ -/** +/** * @file LLIMMgr.h * @brief Container for Instant Messaging * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,7 +40,7 @@ class LLAvatarName; class LLFriendObserver; -class LLCallDialogManager; +class LLCallDialogManager; class LLIMSpeakerMgr; /** @@ -49,12 +49,12 @@ class LLIMSpeakerMgr; class LLSessionTimeoutTimer : public LLEventTimer { public: - LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {} - virtual ~LLSessionTimeoutTimer() {}; - bool tick() override; + LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {} + virtual ~LLSessionTimeoutTimer() {}; + bool tick() override; private: - LLUUID mSessionId; + LLUUID mSessionId; }; @@ -63,30 +63,30 @@ private: */ class LLIMModel : public LLSingleton { - LLSINGLETON(LLIMModel); + LLSINGLETON(LLIMModel); public: typedef std::list chat_message_list_t; struct LLIMSession : public boost::signals2::trackable - { + { typedef enum e_session_type - { // for now we have 4 predefined types for a session - P2P_SESSION, - GROUP_SESSION, - ADHOC_SESSION, - NONE_SESSION, - } SType; - - LLIMSession(const LLUUID& session_id, const std::string& name, - const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg); - virtual ~LLIMSession(); - - void sessionInitReplyReceived(const LLUUID& new_session_id); - void addMessagesFromHistoryCache(const std::list& history); // From local file + { // for now we have 4 predefined types for a session + P2P_SESSION, + GROUP_SESSION, + ADHOC_SESSION, + NONE_SESSION, + } SType; + + LLIMSession(const LLUUID& session_id, const std::string& name, + const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg); + virtual ~LLIMSession(); + + void sessionInitReplyReceived(const LLUUID& new_session_id); + void addMessagesFromHistoryCache(const std::list& history); // From local file void addMessagesFromServerHistory(const LLSD& history, const std::string& target_from, const std::string& target_message, U32 timestamp); // From chat server - void addMessage(const std::string& from, + void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time, @@ -96,135 +96,135 @@ public: void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction); - /** @deprecated */ - static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); + /** @deprecated */ + static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); - bool isOutgoingAdHoc() const; - bool isAdHoc(); - bool isP2P(); - bool isGroupChat(); + bool isOutgoingAdHoc() const; + bool isAdHoc(); + bool isP2P(); + bool isGroupChat(); - bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} - bool isAdHocSessionType() const { return mSessionType == ADHOC_SESSION;} - bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;} + bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} + bool isAdHocSessionType() const { return mSessionType == ADHOC_SESSION;} + bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;} - LLUUID generateOutgoingAdHocHash() const; + LLUUID generateOutgoingAdHocHash() const; - //*TODO make private - /** ad-hoc sessions involve sophisticated chat history file naming schemes */ - void buildHistoryFileName(); + //*TODO make private + /** ad-hoc sessions involve sophisticated chat history file naming schemes */ + void buildHistoryFileName(); - void loadHistory(); + void loadHistory(); - LLUUID mSessionID; - std::string mName; - EInstantMessage mType; - SType mSessionType; - LLUUID mOtherParticipantID; - uuid_vec_t mInitialTargetIDs; - std::string mHistoryFileName; + LLUUID mSessionID; + std::string mName; + EInstantMessage mType; + SType mSessionType; + LLUUID mOtherParticipantID; + uuid_vec_t mInitialTargetIDs; + std::string mHistoryFileName; // Saved messages from the last minute of history read from the local group chat cache file std::string mLastHistoryCacheDateTime; chat_message_list_t mLastHistoryCacheMsgs; - // connection to voice channel state change signal - boost::signals2::connection mVoiceChannelStateChangeConnection; + // connection to voice channel state change signal + boost::signals2::connection mVoiceChannelStateChangeConnection; - //does NOT include system messages and agent's messages - S32 mParticipantUnreadMessageCount; + //does NOT include system messages and agent's messages + S32 mParticipantUnreadMessageCount; - // does include all incoming messages - S32 mNumUnread; + // does include all incoming messages + S32 mNumUnread; chat_message_list_t mMsgs; - LLVoiceChannel* mVoiceChannel; - LLIMSpeakerMgr* mSpeakers; + LLVoiceChannel* mVoiceChannel; + LLIMSpeakerMgr* mSpeakers; + + bool mSessionInitialized; + + //true if calling back the session URI after the session has closed is possible. + //Currently this will be false only for PSTN P2P calls. + bool mCallBackEnabled; - bool mSessionInitialized; + bool mTextIMPossible; + bool mStartCallOnInitialize; - //true if calling back the session URI after the session has closed is possible. - //Currently this will be false only for PSTN P2P calls. - bool mCallBackEnabled; + //if IM session is created for a voice call + bool mStartedAsIMCall; - bool mTextIMPossible; - bool mStartCallOnInitialize; + bool mHasOfflineMessage; - //if IM session is created for a voice call - bool mStartedAsIMCall; + bool mIsDNDsend; - bool mHasOfflineMessage; + private: + void onAdHocNameCache(const LLAvatarName& av_name); - bool mIsDNDsend; + static LLUUID generateHash(const std::set& sorted_uuids); + boost::signals2::connection mAvatarNameCacheConnection; + }; - private: - void onAdHocNameCache(const LLAvatarName& av_name); - static LLUUID generateHash(const std::set& sorted_uuids); - boost::signals2::connection mAvatarNameCacheConnection; - }; - + /** Session id to session object */ + std::map mId2SessionMap; - /** Session id to session object */ - std::map mId2SessionMap; + typedef boost::signals2::signal session_signal_t; + session_signal_t mNewMsgSignal; + session_signal_t mNoUnreadMsgsSignal; - typedef boost::signals2::signal session_signal_t; - session_signal_t mNewMsgSignal; - session_signal_t mNoUnreadMsgsSignal; - - /** - * Find an IM Session corresponding to session_id - * Returns NULL if the session does not exist - */ - LLIMSession* findIMSession(const LLUUID& session_id) const; + /** + * Find an IM Session corresponding to session_id + * Returns NULL if the session does not exist + */ + LLIMSession* findIMSession(const LLUUID& session_id) const; - /** - * Find an Ad-Hoc IM Session with specified participants - * @return first found Ad-Hoc session or NULL if the session does not exist - */ - LLIMSession* findAdHocIMSession(const uuid_vec_t& ids); + /** + * Find an Ad-Hoc IM Session with specified participants + * @return first found Ad-Hoc session or NULL if the session does not exist + */ + LLIMSession* findAdHocIMSession(const uuid_vec_t& ids); - /** - * Rebind session data to a new session id. - */ - void processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id); + /** + * Rebind session data to a new session id. + */ + void processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id); - boost::signals2::connection addNewMsgCallback(const session_signal_t::slot_type& cb ) { return mNewMsgSignal.connect(cb); } - boost::signals2::connection addNoUnreadMsgsCallback(const session_signal_t::slot_type& cb ) { return mNoUnreadMsgsSignal.connect(cb); } + boost::signals2::connection addNewMsgCallback(const session_signal_t::slot_type& cb ) { return mNewMsgSignal.connect(cb); } + boost::signals2::connection addNoUnreadMsgsCallback(const session_signal_t::slot_type& cb ) { return mNoUnreadMsgsSignal.connect(cb); } - /** - * Create new session object in a model - * @param name session name should not be empty, will return false if empty - */ - bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, - const uuid_vec_t& ids, bool voice = false, bool has_offline_msg = false); + /** + * Create new session object in a model + * @param name session name should not be empty, will return false if empty + */ + bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, + const uuid_vec_t& ids, bool voice = false, bool has_offline_msg = false); - bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, - const LLUUID& other_participant_id, bool voice = false, bool has_offline_msg = false); + bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, + const LLUUID& other_participant_id, bool voice = false, bool has_offline_msg = false); - /** - * Remove all session data associated with a session specified by session_id - */ - bool clearSession(const LLUUID& session_id); + /** + * Remove all session data associated with a session specified by session_id + */ + bool clearSession(const LLUUID& session_id); - /** - * Sends no unread messages signal. - */ - void sendNoUnreadMessages(const LLUUID& session_id); + /** + * Sends no unread messages signal. + */ + void sendNoUnreadMessages(const LLUUID& session_id); - /** - * Populate supplied std::list with messages starting from index specified by start_index - */ - void getMessages(const LLUUID& session_id, std::list& messages, int start_index = 0, const bool sendNoUnreadMsgs = true); + /** + * Populate supplied std::list with messages starting from index specified by start_index + */ + void getMessages(const LLUUID& session_id, std::list& messages, int start_index = 0, const bool sendNoUnreadMsgs = true); - /** - * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id - * and also saved into a file if log2file is specified. - * It sends new message signal for each added message. - */ - void addMessage(const LLUUID& session_id, + /** + * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id + * and also saved into a file if log2file is specified. + * It sends new message signal for each added message. + */ + void addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, @@ -240,400 +240,400 @@ public: bool is_region_msg, U32 time_stamp); - /** - * Similar to addMessage(...) above but won't send a signal about a new message added - */ - LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file = true, bool is_region_msg = false, U32 timestamp = 0); - - /** - * Add a system message to an IM Model - */ - void proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text); - - /** - * Get a session's name. - * For a P2P chat - it's an avatar's name, - * For a group chat - it's a group's name - * For an incoming ad-hoc chat - is received from the server and is in a from of " Conference" - * It is updated in LLIMModel::LLIMSession's constructor to localize the "Conference". - */ - const std::string getName(const LLUUID& session_id) const; - - /** - * Get number of unread messages in a session with session_id - * Returns -1 if the session with session_id doesn't exist - */ - const S32 getNumUnread(const LLUUID& session_id) const; - - /** - * Get uuid of other participant in a session with session_id - * Returns LLUUID::null if the session doesn't exist - * - * *TODO what to do with other participants in ad-hoc and group chats? - */ - const LLUUID& getOtherParticipantID(const LLUUID& session_id) const; - - /** - * Get type of a session specified by session_id - * Returns EInstantMessage::IM_COUNT if the session does not exist - */ - EInstantMessage getType(const LLUUID& session_id) const; - - /** - * Get voice channel for the session specified by session_id - * Returns NULL if the session does not exist - */ - LLVoiceChannel* getVoiceChannel(const LLUUID& session_id) const; - - /** - * Get im speaker manager for the session specified by session_id - * Returns NULL if the session does not exist - */ - LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; - - const std::string& getHistoryFileName(const LLUUID& session_id) const; - - static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id); - static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, - const uuid_vec_t& ids, EInstantMessage dialog); - static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); - static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, - const LLUUID& other_participant_id, EInstantMessage dialog); - - // Adds people from speakers list (people with whom you are currently speaking) to the Recent People List - static void addSpeakersToRecent(const LLUUID& im_session_id); - - void testMessages(); - - /** - * Saves an IM message into a file - */ - bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); + /** + * Similar to addMessage(...) above but won't send a signal about a new message added + */ + LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, + const std::string& utf8_text, bool log2file = true, bool is_region_msg = false, U32 timestamp = 0); + + /** + * Add a system message to an IM Model + */ + void proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text); + + /** + * Get a session's name. + * For a P2P chat - it's an avatar's name, + * For a group chat - it's a group's name + * For an incoming ad-hoc chat - is received from the server and is in a from of " Conference" + * It is updated in LLIMModel::LLIMSession's constructor to localize the "Conference". + */ + const std::string getName(const LLUUID& session_id) const; + + /** + * Get number of unread messages in a session with session_id + * Returns -1 if the session with session_id doesn't exist + */ + const S32 getNumUnread(const LLUUID& session_id) const; + + /** + * Get uuid of other participant in a session with session_id + * Returns LLUUID::null if the session doesn't exist + * + * *TODO what to do with other participants in ad-hoc and group chats? + */ + const LLUUID& getOtherParticipantID(const LLUUID& session_id) const; + + /** + * Get type of a session specified by session_id + * Returns EInstantMessage::IM_COUNT if the session does not exist + */ + EInstantMessage getType(const LLUUID& session_id) const; + + /** + * Get voice channel for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLVoiceChannel* getVoiceChannel(const LLUUID& session_id) const; + + /** + * Get im speaker manager for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; + + const std::string& getHistoryFileName(const LLUUID& session_id) const; + + static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id); + static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, + const uuid_vec_t& ids, EInstantMessage dialog); + static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); + static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, + const LLUUID& other_participant_id, EInstantMessage dialog); + + // Adds people from speakers list (people with whom you are currently speaking) to the Recent People List + static void addSpeakersToRecent(const LLUUID& im_session_id); + + void testMessages(); + + /** + * Saves an IM message into a file + */ + bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); private: - /** - * Populate supplied std::list with messages starting from index specified by start_index without - * emitting no unread messages signal. - */ - void getMessagesSilently(const LLUUID& session_id, std::list& messages, int start_index = 0); + /** + * Populate supplied std::list with messages starting from index specified by start_index without + * emitting no unread messages signal. + */ + void getMessagesSilently(const LLUUID& session_id, std::list& messages, int start_index = 0); - /** - * Add message to a list of message associated with session specified by session_id - */ - bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg, U32 timestamp); + /** + * Add message to a list of message associated with session specified by session_id + */ + bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg, U32 timestamp); }; class LLIMSessionObserver { public: - virtual ~LLIMSessionObserver() {} - virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg) = 0; + virtual ~LLIMSessionObserver() {} + virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg) = 0; virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0; - virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0; - virtual void sessionRemoved(const LLUUID& session_id) = 0; - virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0; + virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0; + virtual void sessionRemoved(const LLUUID& session_id) = 0; + virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0; }; class LLIMMgr : public LLSingleton { - LLSINGLETON(LLIMMgr); - friend class LLIMModel; + LLSINGLETON(LLIMMgr); + friend class LLIMModel; public: - enum EInvitationType - { - INVITATION_TYPE_INSTANT_MESSAGE = 0, - INVITATION_TYPE_VOICE = 1, - INVITATION_TYPE_IMMEDIATE = 2 - }; - - - // Add a message to a session. The session can keyed to sesion id - // or agent id. - void addMessage(const LLUUID& session_id, - const LLUUID& target_id, - const std::string& from, - const std::string& msg, - bool is_offline_msg = false, - const std::string& session_name = LLStringUtil::null, - EInstantMessage dialog = IM_NOTHING_SPECIAL, - U32 parent_estate_id = 0, - const LLUUID& region_id = LLUUID::null, - const LLVector3& position = LLVector3::zero, + enum EInvitationType + { + INVITATION_TYPE_INSTANT_MESSAGE = 0, + INVITATION_TYPE_VOICE = 1, + INVITATION_TYPE_IMMEDIATE = 2 + }; + + + // Add a message to a session. The session can keyed to sesion id + // or agent id. + void addMessage(const LLUUID& session_id, + const LLUUID& target_id, + const std::string& from, + const std::string& msg, + bool is_offline_msg = false, + const std::string& session_name = LLStringUtil::null, + EInstantMessage dialog = IM_NOTHING_SPECIAL, + U32 parent_estate_id = 0, + const LLUUID& region_id = LLUUID::null, + const LLVector3& position = LLVector3::zero, bool is_region_msg = false, U32 timestamp = 0); - void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); - - // This adds a session to the talk view. The name is the local - // name of the session, dialog specifies the type of - // session. Since sessions can be keyed off of first recipient or - // initiator, the session can be matched against the id - // provided. If the session exists, it is brought forward. This - // method accepts a group id or an agent id. Specifying id = NULL - // results in an im session to everyone. Returns the uuid of the - // session. - LLUUID addSession(const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, bool voice = false); - - // Adds a session using a specific group of starting agents - // the dialog type is assumed correct. Returns the uuid of the session. - // A session can be added to a floater specified by floater_id. - LLUUID addSession(const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, - const std::vector& ids, bool voice = false, - const LLUUID& floater_id = LLUUID::null); - - /** - * Creates a P2P session with the requisite handle for responding to voice calls. - * - * @param name session name, cannot be null - * @param caller_uri - sip URI of caller. It should be always be passed into the method to avoid - * incorrect working of LLVoiceChannel instances. See EXT-2985. - */ - LLUUID addP2PSession(const std::string& name, - const LLUUID& other_participant_id, - const std::string& voice_session_handle, - const std::string& caller_uri); - - /** - * Leave the session with session id. Send leave session notification - * to the server and removes all associated session data - * @return false if the session with specified id was not exist - */ - bool leaveSession(const LLUUID& session_id); - - void inviteToSession( - const LLUUID& session_id, - const std::string& session_name, - const LLUUID& caller, - const std::string& caller_name, - EInstantMessage type, - EInvitationType inv_type, - const std::string& session_handle = LLStringUtil::null, - const std::string& session_uri = LLStringUtil::null); - - void processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type); - void processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type); - - // automatically start a call once the session has initialized - void autoStartCallOnStartup(const LLUUID& session_id); - - // Calc number of all unread IMs - S32 getNumberOfUnreadIM(); - - /** - * Calculates number of unread IMs from real participants in all stored sessions - */ - S32 getNumberOfUnreadParticipantMessages(); - - // This method is used to go through all active sessions and - // disable all of them. This method is usally called when you are - // forced to log out or similar situations where you do not have a - // good connection. - void disconnectAllSessions(); - - BOOL hasSession(const LLUUID& session_id); - - static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id); - - void clearPendingInvitation(const LLUUID& session_id); - - void processAgentListUpdates(const LLUUID& session_id, const LLSD& body); - LLSD getPendingAgentListUpdates(const LLUUID& session_id); - void addPendingAgentListUpdates( - const LLUUID& sessioN_id, - const LLSD& updates); - void clearPendingAgentListUpdates(const LLUUID& session_id); - - void addSessionObserver(LLIMSessionObserver *); - void removeSessionObserver(LLIMSessionObserver *); - - //show error statuses to the user - void showSessionStartError(const std::string& error_string, const LLUUID session_id); - void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id); - void showSessionForceClose(const std::string& reason, const LLUUID session_id); - static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); - - /** - * Start call in a session - * @return false if voice channel doesn't exist - **/ - bool startCall(const LLUUID& session_id, LLVoiceChannel::EDirection direction = LLVoiceChannel::OUTGOING_CALL); - - /** - * End call in a session - * @return false if voice channel doesn't exist - **/ - bool endCall(const LLUUID& session_id); - - bool isVoiceCall(const LLUUID& session_id); - - void updateDNDMessageStatus(); - - bool isDNDMessageSend(const LLUUID& session_id); - - void setDNDMessageSent(const LLUUID& session_id, bool is_send); - - void addNotifiedNonFriendSessionID(const LLUUID& session_id); - - bool isNonFriendSessionNotified(const LLUUID& session_id); + void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); + + // This adds a session to the talk view. The name is the local + // name of the session, dialog specifies the type of + // session. Since sessions can be keyed off of first recipient or + // initiator, the session can be matched against the id + // provided. If the session exists, it is brought forward. This + // method accepts a group id or an agent id. Specifying id = NULL + // results in an im session to everyone. Returns the uuid of the + // session. + LLUUID addSession(const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, bool voice = false); + + // Adds a session using a specific group of starting agents + // the dialog type is assumed correct. Returns the uuid of the session. + // A session can be added to a floater specified by floater_id. + LLUUID addSession(const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, + const std::vector& ids, bool voice = false, + const LLUUID& floater_id = LLUUID::null); + + /** + * Creates a P2P session with the requisite handle for responding to voice calls. + * + * @param name session name, cannot be null + * @param caller_uri - sip URI of caller. It should be always be passed into the method to avoid + * incorrect working of LLVoiceChannel instances. See EXT-2985. + */ + LLUUID addP2PSession(const std::string& name, + const LLUUID& other_participant_id, + const std::string& voice_session_handle, + const std::string& caller_uri); + + /** + * Leave the session with session id. Send leave session notification + * to the server and removes all associated session data + * @return false if the session with specified id was not exist + */ + bool leaveSession(const LLUUID& session_id); + + void inviteToSession( + const LLUUID& session_id, + const std::string& session_name, + const LLUUID& caller, + const std::string& caller_name, + EInstantMessage type, + EInvitationType inv_type, + const std::string& session_handle = LLStringUtil::null, + const std::string& session_uri = LLStringUtil::null); + + void processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type); + void processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type); + + // automatically start a call once the session has initialized + void autoStartCallOnStartup(const LLUUID& session_id); + + // Calc number of all unread IMs + S32 getNumberOfUnreadIM(); + + /** + * Calculates number of unread IMs from real participants in all stored sessions + */ + S32 getNumberOfUnreadParticipantMessages(); + + // This method is used to go through all active sessions and + // disable all of them. This method is usally called when you are + // forced to log out or similar situations where you do not have a + // good connection. + void disconnectAllSessions(); + + BOOL hasSession(const LLUUID& session_id); + + static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id); + + void clearPendingInvitation(const LLUUID& session_id); + + void processAgentListUpdates(const LLUUID& session_id, const LLSD& body); + LLSD getPendingAgentListUpdates(const LLUUID& session_id); + void addPendingAgentListUpdates( + const LLUUID& sessioN_id, + const LLSD& updates); + void clearPendingAgentListUpdates(const LLUUID& session_id); + + void addSessionObserver(LLIMSessionObserver *); + void removeSessionObserver(LLIMSessionObserver *); + + //show error statuses to the user + void showSessionStartError(const std::string& error_string, const LLUUID session_id); + void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id); + void showSessionForceClose(const std::string& reason, const LLUUID session_id); + static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); + + /** + * Start call in a session + * @return false if voice channel doesn't exist + **/ + bool startCall(const LLUUID& session_id, LLVoiceChannel::EDirection direction = LLVoiceChannel::OUTGOING_CALL); + + /** + * End call in a session + * @return false if voice channel doesn't exist + **/ + bool endCall(const LLUUID& session_id); + + bool isVoiceCall(const LLUUID& session_id); + + void updateDNDMessageStatus(); + + bool isDNDMessageSend(const LLUUID& session_id); + + void setDNDMessageSent(const LLUUID& session_id, bool is_send); + + void addNotifiedNonFriendSessionID(const LLUUID& session_id); + + bool isNonFriendSessionNotified(const LLUUID& session_id); private: - /** - * Remove data associated with a particular session specified by session_id - */ - void removeSession(const LLUUID& session_id); + /** + * Remove data associated with a particular session specified by session_id + */ + void removeSession(const LLUUID& session_id); - // This simple method just iterates through all of the ids, and - // prints a simple message if they are not online. Used to help - // reduce 'hello' messages to the linden employees unlucky enough - // to have their calling card in the default inventory. - void noteOfflineUsers(const LLUUID& session_id, const std::vector& ids); - void noteMutedUsers(const LLUUID& session_id, const std::vector& ids); + // This simple method just iterates through all of the ids, and + // prints a simple message if they are not online. Used to help + // reduce 'hello' messages to the linden employees unlucky enough + // to have their calling card in the default inventory. + void noteOfflineUsers(const LLUUID& session_id, const std::vector& ids); + void noteMutedUsers(const LLUUID& session_id, const std::vector& ids); - void processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing); + void processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing); - static void onInviteNameLookup(LLSD payload, const LLUUID& id, const LLAvatarName& name); + static void onInviteNameLookup(LLSD payload, const LLUUID& id, const LLAvatarName& name); - void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg); + void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg); //Triggers when a session has already been added void notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); - void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id); - void notifyObserverSessionRemoved(const LLUUID& session_id); - void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); + void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id); + void notifyObserverSessionRemoved(const LLUUID& session_id); + void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); private: - - typedef std::list session_observers_list_t; - session_observers_list_t mSessionObservers; - - // EXP-901 - // If "Only friends and groups can IM me" option is ON but the user got message from non-friend, - // the user should be notified that to be able to see this message the option should be OFF. - // This set stores session IDs in which user was notified. Need to store this IDs so that the user - // be notified only one time per session with non-friend. - typedef std::set notified_non_friend_sessions_t; - notified_non_friend_sessions_t mNotifiedNonFriendSessions; - - LLSD mPendingInvitations; - LLSD mPendingAgentListUpdates; + + typedef std::list session_observers_list_t; + session_observers_list_t mSessionObservers; + + // EXP-901 + // If "Only friends and groups can IM me" option is ON but the user got message from non-friend, + // the user should be notified that to be able to see this message the option should be OFF. + // This set stores session IDs in which user was notified. Need to store this IDs so that the user + // be notified only one time per session with non-friend. + typedef std::set notified_non_friend_sessions_t; + notified_non_friend_sessions_t mNotifiedNonFriendSessions; + + LLSD mPendingInvitations; + LLSD mPendingAgentListUpdates; }; class LLCallDialogManager : public LLSingleton { - LLSINGLETON(LLCallDialogManager); - ~LLCallDialogManager(); + LLSINGLETON(LLCallDialogManager); + ~LLCallDialogManager(); public: - // static for convinience - static void onVoiceChannelChanged(const LLUUID &session_id); - static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); + // static for convinience + static void onVoiceChannelChanged(const LLUUID &session_id); + static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); private: - void initSingleton() override; - void onVoiceChannelChangedInt(const LLUUID &session_id); - void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); + void initSingleton() override; + void onVoiceChannelChangedInt(const LLUUID &session_id); + void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); protected: - std::string mPreviousSessionlName; - std::string mCurrentSessionlName; - LLIMModel::LLIMSession* mSession; - LLVoiceChannel::EState mOldState; + std::string mPreviousSessionlName; + std::string mCurrentSessionlName; + LLIMModel::LLIMSession* mSession; + LLVoiceChannel::EState mOldState; }; class LLCallDialog : public LLDockableFloater { public: - LLCallDialog(const LLSD& payload); - virtual ~LLCallDialog(); + LLCallDialog(const LLSD& payload); + virtual ~LLCallDialog(); + + virtual BOOL postBuild(); + + void dockToToolbarButton(const std::string& toolbarButtonName); - virtual BOOL postBuild(); + // check timer state + /*virtual*/ void draw(); + /*virtual*/ void onOpen(const LLSD& key); - void dockToToolbarButton(const std::string& toolbarButtonName); - - // check timer state - /*virtual*/ void draw(); - /*virtual*/ void onOpen(const LLSD& key); - protected: - // lifetime timer for a notification - LLTimer mLifetimeTimer; - // notification's lifetime in seconds - S32 mLifetime; - static const S32 DEFAULT_LIFETIME = 5; - virtual bool lifetimeHasExpired(); - virtual void onLifetimeExpired(); - - /** - * Sets icon depend on session. - * - * If passed session_id is a group id group icon will be shown, otherwise avatar icon for participant_id - * - * @param session_id - UUID of session - * @param participant_id - UUID of other participant - */ - void setIcon(const LLSD& session_id, const LLSD& participant_id); - - LLSD mPayload; + // lifetime timer for a notification + LLTimer mLifetimeTimer; + // notification's lifetime in seconds + S32 mLifetime; + static const S32 DEFAULT_LIFETIME = 5; + virtual bool lifetimeHasExpired(); + virtual void onLifetimeExpired(); + + /** + * Sets icon depend on session. + * + * If passed session_id is a group id group icon will be shown, otherwise avatar icon for participant_id + * + * @param session_id - UUID of session + * @param participant_id - UUID of other participant + */ + void setIcon(const LLSD& session_id, const LLSD& participant_id); + + LLSD mPayload; private: - LLDockControl::DocAt getDockControlPos(const std::string& toolbarButtonName); + LLDockControl::DocAt getDockControlPos(const std::string& toolbarButtonName); }; class LLIncomingCallDialog : public LLCallDialog { public: - LLIncomingCallDialog(const LLSD& payload); - ~LLIncomingCallDialog() - { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - } - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - - static void onAccept(void* user_data); - static void onReject(void* user_data); - static void onStartIM(void* user_data); - - static void processCallResponse(S32 response, const LLSD& payload); + LLIncomingCallDialog(const LLSD& payload); + ~LLIncomingCallDialog() + { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + } + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + + static void onAccept(void* user_data); + static void onReject(void* user_data); + static void onStartIM(void* user_data); + + static void processCallResponse(S32 response, const LLSD& payload); private: - void setCallerName(const std::string& ui_title, - const std::string& ui_label, - const std::string& call_type); - void onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name, - const std::string& call_type); + void setCallerName(const std::string& ui_title, + const std::string& ui_label, + const std::string& call_type); + void onAvatarNameCache(const LLUUID& agent_id, + const LLAvatarName& av_name, + const std::string& call_type); - boost::signals2::connection mAvatarNameCacheConnection; + boost::signals2::connection mAvatarNameCacheConnection; - /*virtual*/ void onLifetimeExpired(); + /*virtual*/ void onLifetimeExpired(); }; class LLOutgoingCallDialog : public LLCallDialog { public: - LLOutgoingCallDialog(const LLSD& payload); + LLOutgoingCallDialog(const LLSD& payload); - /*virtual*/ BOOL postBuild(); - void show(const LLSD& key); + /*virtual*/ BOOL postBuild(); + void show(const LLSD& key); - static void onCancel(void* user_data); - static const LLUUID OCD_KEY; + static void onCancel(void* user_data); + static const LLUUID OCD_KEY; private: - // hide all text boxes - void hideAllText(); + // hide all text boxes + void hideAllText(); }; // Globals diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 7d1252ee31..f0dcdf01c1 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llinventoryfunctions.cpp * @brief Implementation of the inventory view and associated stuff. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -152,19 +152,19 @@ S32 count_stock_folders(LLInventoryModel::cat_array_t& categories) // Helper funtion : Count the number of items (not folders) in the descending hierarchy S32 count_descendants_items(const LLUUID& cat_id) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + S32 count = item_array->size(); - + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { - LLViewerInventoryCategory* category = *iter; + LLViewerInventoryCategory* category = *iter; count += count_descendants_items(category->getUUID()); } - + return count; } @@ -179,7 +179,7 @@ bool contains_nocopy_items(const LLUUID& id) LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(id,cat_array,item_array); - + // Check all the items: returns true upon encountering a nocopy item for (LLInventoryModel::item_array_t::iterator iter = item_array->begin(); iter != item_array->end(); iter++) { @@ -190,7 +190,7 @@ bool contains_nocopy_items(const LLUUID& id) return true; } } - + // Check all the sub folders recursively for (LLInventoryModel::cat_array_t::iterator iter = cat_array->begin(); iter != cat_array->end(); iter++) { @@ -203,14 +203,14 @@ bool contains_nocopy_items(const LLUUID& id) } else { - LLInventoryItem* item = gInventory.getItem(id); + LLInventoryItem* item = gInventory.getItem(id); LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item; if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { return true; } } - + // Exit without meeting a nocopy item return false; } @@ -218,21 +218,21 @@ bool contains_nocopy_items(const LLUUID& id) // Generates a string containing the path to the item specified by id. void append_path(const LLUUID& id, std::string& path) { - std::string temp; - const LLInventoryObject* obj = gInventory.getObject(id); - LLUUID parent_id; - if(obj) parent_id = obj->getParentUUID(); - std::string forward_slash("/"); - while(obj) - { - obj = gInventory.getCategory(parent_id); - if(obj) - { - temp.assign(forward_slash + obj->getName() + temp); - parent_id = obj->getParentUUID(); - } - } - path.append(temp); + std::string temp; + const LLInventoryObject* obj = gInventory.getObject(id); + LLUUID parent_id; + if(obj) parent_id = obj->getParentUUID(); + std::string forward_slash("/"); + while(obj) + { + obj = gInventory.getCategory(parent_id); + if(obj) + { + temp.assign(forward_slash + obj->getName() + temp); + parent_id = obj->getParentUUID(); + } + } + path.append(temp); } // Generates a string containing the path name of the object. @@ -273,10 +273,10 @@ void update_marketplace_folder_hierarchy(const LLUUID cat_id) gInventory.addChangedMask(LLInventoryObserver::LABEL, cat_id); // Update all descendent folders down - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { @@ -291,9 +291,9 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc // When changing the marketplace status of an item, we usually have to change the status of all // folders in the same listing. This is because the display of each folder is affected by the // overall status of the whole listing. - // Consequently, the only way to correctly update an item anywhere in the marketplace is to + // Consequently, the only way to correctly update an item anywhere in the marketplace is to // update the whole listing from its listing root. - // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth + // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth // is limited to 4. // We also take care of degenerated cases so we don't update all folders in the inventory by mistake. @@ -303,7 +303,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc { return; } - + // Grab marketplace listing data for this item S32 depth = depth_nesting_in_marketplace(cur_uuid); if (depth > 0) @@ -312,7 +312,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc LLUUID listing_uuid = nested_parent_id(cur_uuid, depth); LLViewerInventoryCategory* listing_cat = gInventory.getCategory(listing_uuid); bool listing_cat_loaded = listing_cat != NULL && listing_cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; - + // Verify marketplace data consistency for this listing if (perform_consistency_enforcement && listing_cat_loaded @@ -336,7 +336,7 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc LLMarketplaceData::instance().activateListing(listing_uuid, false,1); } } - + // Check if the count on hand needs to be updated on SLM if (perform_consistency_enforcement && listing_cat_loaded @@ -377,10 +377,10 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc void update_all_marketplace_count(const LLUUID& cat_id) { // Get all descendent folders down - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { @@ -412,19 +412,19 @@ void update_all_marketplace_count() void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) { - LLViewerInventoryCategory* cat; + LLViewerInventoryCategory* cat; - if (!model || - !get_is_category_renameable(model, cat_id) || - (cat = model->getCategory(cat_id)) == NULL || - cat->getName() == new_name) - { - return; - } + if (!model || + !get_is_category_renameable(model, cat_id) || + (cat = model->getCategory(cat_id)) == NULL || + cat->getName() == new_name) + { + return; + } - LLSD updates; - updates["name"] = new_name; - update_inventory_category(cat_id, updates, NULL); + LLSD updates; + updates["name"] = new_name; + update_inventory_category(cat_id, updates, NULL); } void copy_inventory_category(LLInventoryModel* model, @@ -448,7 +448,7 @@ void copy_inventory_category(LLInventoryModel* model, bool move_no_copy_items, inventory_func_type callback) { - // Create the initial folder + // Create the initial folder inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID &new_id) { copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items); @@ -457,7 +457,7 @@ void copy_inventory_category(LLInventoryModel* model, callback(new_id); } }; - gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); + gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); } void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) @@ -469,21 +469,21 @@ void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items) { - model->notifyObservers(); + model->notifyObservers(); - // We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... - LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); + // We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... + LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); - // Get the content of the folder - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(), cat_array, item_array); + // Get the content of the folder + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(), cat_array, item_array); - // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder - if (root_copy_id.isNull()) - { - LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); - } + // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder + if (root_copy_id.isNull()) + { + LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); + } LLPointer cb; if (root_copy_id.isNull()) @@ -495,348 +495,348 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); } - // Copy all the items - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; - - if (item->getIsLinkType()) - { - link_inventory_object(new_cat_uuid, item->getLinkedUUID(), cb); - } - else if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) - { - // If the item is nocopy, we do nothing or, optionally, move it - if (move_no_copy_items) - { - // Reparent the item - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; - gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); - } + // Copy all the items + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; + + if (item->getIsLinkType()) + { + link_inventory_object(new_cat_uuid, item->getLinkedUUID(), cb); + } + else if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // If the item is nocopy, we do nothing or, optionally, move it + if (move_no_copy_items) + { + // Reparent the item + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; + gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); + } if (root_copy_id.isNull()) { // Decrement the count in root_id since that one item won't be copied over LLMarketplaceData::instance().decrementValidationWaiting(root_id); } - } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - new_cat_uuid, - std::string(), - cb); - } - } - - // Copy all the folders - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLViewerInventoryCategory* category = *iter; - if (category->getUUID() != root_id) - { - copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); - } - } + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + new_cat_uuid, + std::string(), + cb); + } + } + + // Copy all the folders + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLViewerInventoryCategory* category = *iter; + if (category->getUUID() != root_id) + { + copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); + } + } } class LLInventoryCollectAllItems : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + return true; + } }; BOOL get_is_parent_to_worn_item(const LLUUID& id) { - const LLViewerInventoryCategory* cat = gInventory.getCategory(id); - if (!cat) - { - return FALSE; - } + const LLViewerInventoryCategory* cat = gInventory.getCategory(id); + if (!cat) + { + return FALSE; + } - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryCollectAllItems collect_all; - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryCollectAllItems collect_all; + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all); - for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) - { - const LLViewerInventoryItem * const item = *it; + for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) + { + const LLViewerInventoryItem * const item = *it; - llassert(item->getIsLinkType()); + llassert(item->getIsLinkType()); - LLUUID linked_id = item->getLinkedUUID(); - const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id); + LLUUID linked_id = item->getLinkedUUID(); + const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id); - if (linked_item) - { - LLUUID parent_id = linked_item->getParentUUID(); + if (linked_item) + { + LLUUID parent_id = linked_item->getParentUUID(); - while (!parent_id.isNull()) - { - LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id); + while (!parent_id.isNull()) + { + LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id); - if (cat == parent_cat) - { - return TRUE; - } + if (cat == parent_cat) + { + return TRUE; + } - parent_id = parent_cat->getParentUUID(); - } - } - } + parent_id = parent_cat->getParentUUID(); + } + } + } - return FALSE; + return FALSE; } BOOL get_is_item_worn(const LLUUID& id) { - const LLViewerInventoryItem* item = gInventory.getItem(id); - if (!item) - return FALSE; + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + return FALSE; if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID())) { return FALSE; } - // Consider the item as worn if it has links in COF. - if (LLAppearanceMgr::instance().isLinkedInCOF(id)) - { - return TRUE; - } - - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - { - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) - return TRUE; - break; - } - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(gAgentWearables.isWearingItem(item->getLinkedUUID())) - return TRUE; - break; - case LLAssetType::AT_GESTURE: - if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID())) - return TRUE; - break; - default: - break; - } - return FALSE; + // Consider the item as worn if it has links in COF. + if (LLAppearanceMgr::instance().isLinkedInCOF(id)) + { + return TRUE; + } + + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + { + if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) + return TRUE; + break; + } + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if(gAgentWearables.isWearingItem(item->getLinkedUUID())) + return TRUE; + break; + case LLAssetType::AT_GESTURE: + if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID())) + return TRUE; + break; + default: + break; + } + return FALSE; } BOOL get_can_item_be_worn(const LLUUID& id) { - const LLViewerInventoryItem* item = gInventory.getItem(id); - if (!item) - return FALSE; - - if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) - { - // an item having links in COF (i.e. a worn item) - return FALSE; - } - - if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) - { - // a non-link object in COF (should not normally happen) - return FALSE; - } - - const LLUUID trash_id = gInventory.findCategoryUUIDForType( - LLFolderType::FT_TRASH); - - // item can't be worn if base obj in trash, see EXT-7015 - if (gInventory.isObjectDescendentOf(item->getLinkedUUID(), - trash_id)) - { - return false; - } - - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - { - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) - { - // Already being worn - return FALSE; - } - else - { - // Not being worn yet. - return TRUE; - } - break; - } - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(gAgentWearables.isWearingItem(item->getLinkedUUID())) - { - // Already being worn - return FALSE; - } - else - { - // Not being worn yet. - return TRUE; - } - break; - default: - break; - } - return FALSE; + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + return FALSE; + + if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) + { + // an item having links in COF (i.e. a worn item) + return FALSE; + } + + if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF())) + { + // a non-link object in COF (should not normally happen) + return FALSE; + } + + const LLUUID trash_id = gInventory.findCategoryUUIDForType( + LLFolderType::FT_TRASH); + + // item can't be worn if base obj in trash, see EXT-7015 + if (gInventory.isObjectDescendentOf(item->getLinkedUUID(), + trash_id)) + { + return false; + } + + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + { + if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID())) + { + // Already being worn + return FALSE; + } + else + { + // Not being worn yet. + return TRUE; + } + break; + } + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if(gAgentWearables.isWearingItem(item->getLinkedUUID())) + { + // Already being worn + return FALSE; + } + else + { + // Not being worn yet. + return TRUE; + } + break; + default: + break; + } + return FALSE; } BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) { - if (!model) - { - return FALSE; - } - - // Can't delete an item that's in the library. - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } - - // Disable delete from COF folder; have users explicitly choose "detach/take off", - // unless the item is not worn but in the COF (i.e. is bugged). - if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) - { - if (get_is_item_worn(id)) - { - return FALSE; - } - } - - const LLInventoryObject *obj = model->getItem(id); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - if (get_is_item_worn(id)) - { - return FALSE; - } - return TRUE; + if (!model) + { + return FALSE; + } + + // Can't delete an item that's in the library. + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } + + // Disable delete from COF folder; have users explicitly choose "detach/take off", + // unless the item is not worn but in the COF (i.e. is bugged). + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) + { + if (get_is_item_worn(id)) + { + return FALSE; + } + } + + const LLInventoryObject *obj = model->getItem(id); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } + if (get_is_item_worn(id)) + { + return FALSE; + } + return TRUE; } bool get_is_item_editable(const LLUUID& inv_item_id) { - if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) - { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - return gAgentWearables.isWearableModifiable(inv_item_id); - case LLAssetType::AT_OBJECT: - return true; - default: + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gAgentWearables.isWearableModifiable(inv_item_id); + case LLAssetType::AT_OBJECT: + return true; + default: return false;; - } - } - return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; + } + } + return gAgentAvatarp->getWornAttachment(inv_item_id) != nullptr; } void handle_item_edit(const LLUUID& inv_item_id) { - if (get_is_item_editable(inv_item_id)) - { - if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) - { - switch (inv_item->getType()) - { - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - LLAgentWearables::editWearable(inv_item_id); - break; - case LLAssetType::AT_OBJECT: - handle_attachment_edit(inv_item_id); - break; - default: - break; - } - } - else - { - handle_attachment_edit(inv_item_id); - } - } + if (get_is_item_editable(inv_item_id)) + { + if (const LLInventoryItem* inv_item = gInventory.getLinkedItem(inv_item_id)) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + LLAgentWearables::editWearable(inv_item_id); + break; + case LLAssetType::AT_OBJECT: + handle_attachment_edit(inv_item_id); + break; + default: + break; + } + } + else + { + handle_attachment_edit(inv_item_id); + } + } } BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) { - // NOTE: This function doesn't check the folder's children. - // See LLFolderBridge::isItemRemovable for a function that does - // consider the children. + // NOTE: This function doesn't check the folder's children. + // See LLFolderBridge::isItemRemovable for a function that does + // consider the children. - if (!model) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - return FALSE; - } + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } - if (!isAgentAvatarValid()) return FALSE; + if (!isAgentAvatarValid()) return FALSE; - const LLInventoryCategory* category = model->getCategory(id); - if (!category) - { - return FALSE; - } + const LLInventoryCategory* category = model->getCategory(id); + if (!category) + { + return FALSE; + } - const LLFolderType::EType folder_type = category->getPreferredType(); - - if (LLFolderType::lookupIsProtectedType(folder_type)) - { - return FALSE; - } + const LLFolderType::EType folder_type = category->getPreferredType(); - // Can't delete the outfit that is currently being worn. - if (folder_type == LLFolderType::FT_OUTFIT) - { - const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); - if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) - { - return FALSE; - } - } + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + return FALSE; + } - return TRUE; + // Can't delete the outfit that is currently being worn. + if (folder_type == LLFolderType::FT_OUTFIT) + { + const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) + { + return FALSE; + } + } + + return TRUE; } BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) { - if (!model) - { - return FALSE; - } + if (!model) + { + return FALSE; + } - LLViewerInventoryCategory* cat = model->getCategory(id); + LLViewerInventoryCategory* cat = model->getCategory(id); - if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && - cat->getOwnerID() == gAgent.getID()) - { - return TRUE; - } - return FALSE; + if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && + cat->getOwnerID() == gAgent.getID()) + { + return TRUE; + } + return FALSE; } void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id) @@ -844,13 +844,13 @@ void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id) LLSD params; params["id"] = item_uuid; params["object"] = object_id; - + LLFloaterReg::showInstance("item_properties", params); } void show_item_profile(const LLUUID& item_uuid) { - LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); + LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid); LLFloaterReg::showInstance("item_properties", LLSD().with("id", linked_uuid)); } @@ -877,7 +877,7 @@ void show_item_original(const LLUUID& item_uuid) LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); if (sidepanel_inventory) { LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); @@ -920,20 +920,20 @@ void show_item_original(const LLUUID& item_uuid) void reset_inventory_filter() { - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); - if (sidepanel_inventory) - { - LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); - if (main_inventory) - { - main_inventory->onFilterEdit(""); - } - } + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); + if (sidepanel_inventory) + { + LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); + if (main_inventory) + { + main_inventory->onFilterEdit(""); + } + } } void open_marketplace_listings() { - LLFloaterReg::showInstance("marketplace_listings"); + LLFloaterReg::showInstance("marketplace_listings"); } ///---------------------------------------------------------------------------- @@ -960,7 +960,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid) { return -1; } - + // Iterate through the parents till we hit the marketplace listings root // Note that the marketplace listings root itself will return 0 S32 depth = 0; @@ -1062,13 +1062,13 @@ S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) } } } - + // In all other cases, the stock count is the min of stock folders count found in the descendents // "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder in the hierarchy has a count that cannot be evaluated at this time (folder not up to date) - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); - + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); + // "COMPUTE_STOCK_INFINITE" denotes a folder that doesn't countain any stock folders in its descendents S32 curr_count = COMPUTE_STOCK_INFINITE; @@ -1083,147 +1083,147 @@ S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) curr_count = count; } } - + return curr_count; } // local helper bool can_move_to_marketplace(LLInventoryItem* inv_item, std::string& tooltip_msg, bool resolve_links) { - // Collapse links directly to items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); // Linked items and folders cannot be put for sale if (linked_category || linked_item) { - tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); + tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); return false; } - + // A category is always considered as passing... if (linked_category != NULL) - { + { return true; - } - + } + // Take the linked item if necessary if (linked_item != NULL) - { - inv_item = linked_item; - } - + { + inv_item = linked_item; + } + // Check that the agent has transfer permission on the item: this is required as a resident cannot // put on sale items she cannot transfer. Proceed with move if we have permission. - bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); - if (!allow_transfer) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); - return false; - } - + bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + if (!allow_transfer) + { + tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); + return false; + } + // Check worn/not worn status: worn items cannot be put on the marketplace - bool worn = get_is_item_worn(inv_item->getUUID()); - if (worn) - { - tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); - return false; - } + bool worn = get_is_item_worn(inv_item->getUUID()); + if (worn) + { + tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); + return false; + } // Check library status: library items cannot be put on the marketplace - if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) + if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - return false; + tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + return false; } // Check type: for the moment, calling cards cannot be put on the marketplace - bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); - if (calling_card) - { - tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); - return false; - } - - return true; + bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); + if (calling_card) + { + tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); + return false; + } + + return true; } // local helper // Returns the max tree length (in folder nodes) down from the argument folder int get_folder_levels(LLInventoryCategory* inv_cat) { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - - int max_child_levels = 0; - - for (S32 i=0; i < cats->size(); ++i) - { - LLInventoryCategory* category = cats->at(i); - max_child_levels = llmax(max_child_levels, get_folder_levels(category)); - } - - return 1 + max_child_levels; + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + int max_child_levels = 0; + + for (S32 i=0; i < cats->size(); ++i) + { + LLInventoryCategory* category = cats->at(i); + max_child_levels = llmax(max_child_levels, get_folder_levels(category)); + } + + return 1 + max_child_levels; } // local helper // Returns the distance (in folder nodes) between the ancestor and its descendant. Returns -1 if not related. int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) { - int depth = 0; - - if (ancestor_id == descendant_id) return depth; - - const LLInventoryCategory* category = gInventory.getCategory(descendant_id); - - while (category) - { - LLUUID parent_id = category->getParentUUID(); - - if (parent_id.isNull()) break; - - depth++; - - if (parent_id == ancestor_id) return depth; - - category = gInventory.getCategory(parent_id); - } - - LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; - return -1; + int depth = 0; + + if (ancestor_id == descendant_id) return depth; + + const LLInventoryCategory* category = gInventory.getCategory(descendant_id); + + while (category) + { + LLUUID parent_id = category->getParentUUID(); + + if (parent_id.isNull()) break; + + depth++; + + if (parent_id == ancestor_id) return depth; + + category = gInventory.getCategory(parent_id); + } + + LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; + return -1; } // local helper // Returns true if all items within the argument folder are fit for sale, false otherwise bool has_correct_permissions_for_sale(LLInventoryCategory* cat, std::string& error_msg) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - - LLInventoryModel::item_array_t item_array_copy = *item_array; - - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + + LLInventoryModel::item_array_t item_array_copy = *item_array; + + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; if (!can_move_to_marketplace(item, error_msg, false)) { return false; } - } - - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLInventoryCategory* category = *iter; - if (!has_correct_permissions_for_sale(category, error_msg)) + } + + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + if (!has_correct_permissions_for_sale(category, error_msg)) { return false; } - } + } return true; } @@ -1246,18 +1246,18 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve { accept = can_move_to_marketplace(inv_item, tooltip_msg, true); } - + // Check that the total amount of items won't violate the max limit on the marketplace if (accept) { // If the dest folder is a stock folder, we do not count the incoming items toward the total (stock items are seen as one) int existing_item_count = (move_in_stock ? 0 : bundle_size); - + // If the dest folder is a stock folder, we do assume that the incoming items are also stock items (they should anyway) int existing_stock_count = (move_in_stock ? bundle_size : 0); - + int existing_folder_count = 0; - + // Get the version folder: that's where the counts start from const LLViewerInventoryCategory * version_folder = ((root_folder && (root_folder != dest_folder)) ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); @@ -1271,13 +1271,13 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve LLInventoryModel::cat_array_t existing_categories; LLInventoryModel::item_array_t existing_items; - + gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - + existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_stock_count += count_stock_items(existing_items); existing_folder_count += existing_categories.size(); - + // If the incoming item is a nocopy (stock) item, we need to consider that it will create a stock folder if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && !move_in_stock) { @@ -1285,7 +1285,7 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve existing_folder_count += 1; } } - + if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) { LLStringUtil::format_map_t args; @@ -1321,7 +1321,7 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size, bool check_items, bool from_paste) { bool accept = true; - + // Compute the nested folders level we'll add into with that incoming folder int incoming_folder_depth = get_folder_levels(inv_cat); // Compute the nested folders level we're inserting ourselves in @@ -1330,7 +1330,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn // Get the version folder: that's where the folders and items counts start from const LLViewerInventoryCategory * version_folder = (insertion_point_folder_depth >= 2 ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); - + // Compare the whole with the nested folders depth limit // Note: substract 2 as we leave root and version folder out of the count threshold if ((incoming_folder_depth + insertion_point_folder_depth - 2) > (S32)(gSavedSettings.getU32("InventoryOutboxMaxFolderDepth"))) @@ -1341,20 +1341,20 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels", args); accept = false; } - + if (accept) { LLInventoryModel::cat_array_t descendent_categories; LLInventoryModel::item_array_t descendent_items; gInventory.collectDescendents(inv_cat->getUUID(), descendent_categories, descendent_items, FALSE); - + int dragged_folder_count = descendent_categories.size() + bundle_size; // Note: We assume that we're moving a bunch of folders in. That might be wrong... int dragged_item_count = count_copyable_items(descendent_items) + count_stock_folders(descendent_categories); int dragged_stock_count = count_stock_items(descendent_items); int existing_item_count = 0; int existing_stock_count = 0; int existing_folder_count = 0; - + if (version_folder) { if (!from_paste && gInventory.isObjectDescendentOf(inv_cat->getUUID(), version_folder->getUUID())) @@ -1364,21 +1364,21 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn dragged_item_count = 0; dragged_stock_count = 0; } - + // Tally the total number of categories and items inside the root folder LLInventoryModel::cat_array_t existing_categories; LLInventoryModel::item_array_t existing_items; gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - + existing_folder_count += existing_categories.size(); existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_stock_count += count_stock_items(existing_items); } - + const int total_folder_count = existing_folder_count + dragged_folder_count; const int total_item_count = existing_item_count + dragged_item_count; const int total_stock_count = existing_stock_count + dragged_stock_count; - + if (total_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) { LLStringUtil::format_map_t args; @@ -1403,7 +1403,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args); accept = false; } - + // Now check that each item in the folder can be moved in the marketplace if (accept && check_items) { @@ -1418,7 +1418,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn } } } - + return accept; } @@ -1429,33 +1429,33 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol S32 depth = depth_nesting_in_marketplace(dest_folder); if (depth < 0) { - LLSD subs; - subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); - LLNotificationsUtil::add("MerchantPasteFailed", subs); + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } // We will collapse links into items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); - - if (linked_category != NULL) - { + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); + + if (linked_category != NULL) + { // Move the linked folder directly - return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); - } - else - { + return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); + } + else + { // Grab the linked item if any - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); viewer_inv_item = (linked_item != NULL ? linked_item : viewer_inv_item); - + // If we want to copy but the item is no copy, fail silently (this is a common case that doesn't warrant notification) if (copy && !viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { return false; } - + // Check that the agent has transfer permission on the item: this is required as a resident cannot // put on sale items she cannot transfer. Proceed with move if we have permission. std::string error_msg; @@ -1585,7 +1585,7 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol return false; } } - + open_marketplace_listings(); return true; } @@ -1607,7 +1607,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } - + // Get the parent folder of the moved item : we may have to update it LLUUID src_folder = inv_cat->getParentUUID(); @@ -1638,14 +1638,14 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU LLNotificationsUtil::add("MerchantPasteFailed", subs); return false; } - + open_marketplace_listings(); return true; } bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCategory* cat2) { - return cat1->getName().compare(cat2->getName()) < 0; + return cat1->getName().compare(cat2->getName()) < 0; } // Make all relevant business logic checks on the marketplace listings starting with the folder as argument. @@ -1667,7 +1667,7 @@ void validate_marketplacelistings( { // Get the type and the depth of the folder LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat); - const LLFolderType::EType folder_type = cat->getPreferredType(); + const LLFolderType::EType folder_type = cat->getPreferredType(); if (depth < 0) { // If the depth argument was not provided, evaluate the depth directly @@ -1680,7 +1680,7 @@ void validate_marketplacelistings( depth = 1; fix_hierarchy = false; } - + // Set the indentation for print output (typically, audit button in marketplace folder floater) std::string indent; for (int i = 1; i < depth; i++) @@ -1703,7 +1703,7 @@ void validate_marketplacelistings( } } } - + // Check out that stock folders are at the right level if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth <= 2)) { @@ -1752,28 +1752,28 @@ void validate_marketplacelistings( } } } - + // Item sorting and validation : sorting and moving the various stock items is complicated as the set of constraints is high // We need to: // * separate non stock items, stock items per types in different folders // * have stock items nested at depth 2 at least // * never ever move the non-stock items - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - + + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + // We use a composite (type,permission) key on that map to store UUIDs of items of same (type,permissions) std::map > items_vector; // Parse the items and create vectors of item UUIDs sorting copyable items and stock items of various types bool has_bad_items = false; - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) item; - + // Test but skip items that shouldn't be there to start with, raise an error message for those std::string error_msg; if (!can_move_to_marketplace(item, error_msg, false)) @@ -1797,13 +1797,13 @@ void validate_marketplacelistings( } U32 key = (((U32)(type) & 0xFF) << 24) | (perms & 0xFFFFFF); items_vector[key].push_back(viewer_inv_item->getUUID()); - } - + } + // How many types of items? Which type is it if only one? S32 count = items_vector.size(); U32 default_key = (U32)(LLInventoryType::IT_COUNT) << 24; // This is the key for any normal copyable item U32 unique_key = (count == 1 ? items_vector.begin()->first : default_key); // The key in the case of one item type only - + // If we have no items in there (only folders or empty), analyze a bit further if ((count == 0) && !has_bad_items) { @@ -2029,7 +2029,7 @@ void validate_marketplacelistings( } } } - + // Clean up if (viewer_cat->getDescendentCount() == 0) { @@ -2051,15 +2051,15 @@ void validate_marketplacelistings( // Recursion : Perform the same validation on each nested folder gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; // Sort the folders in alphabetical order first std::sort(cat_array_copy.begin(), cat_array_copy.end(), sort_alpha); - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLInventoryCategory* category = *iter; - validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); - } + + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); + } update_marketplace_category(cat->getUUID(), true, true); if (notify_observers) @@ -2071,22 +2071,22 @@ void validate_marketplacelistings( void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) { - LLInventoryItem* inv_item = gInventory.getItem(item_id); - if (inv_item) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); + LLInventoryItem* inv_item = gInventory.getItem(item_id); + if (inv_item) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); - LLPointer new_item = new LLViewerInventoryItem(inv_item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } + LLPointer new_item = new LLViewerInventoryItem(inv_item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } } void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids) @@ -2114,7 +2114,7 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); if (sidepanel_inventory) { if (sidepanel_inventory->getActivePanel()) @@ -2301,7 +2301,7 @@ std::string get_localized_folder_name(LLUUID cat_uuid) LLTrans::findString(localized_root_name, std::string("InvFolder ") + cat->getName(), LLSD()); } } - + return localized_root_name; } @@ -2531,62 +2531,62 @@ LLMarketplaceValidator::ValidationRequest::ValidationRequest( // static bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryItem* item) { - if (!item) - return false; + if (!item) + return false; - switch(item->getType()) - { - case LLAssetType::AT_OBJECT: - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if (!get_is_item_worn(item->getUUID())) - return true; - break; - default: - return true; - break; - } - return false; + switch(item->getType()) + { + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + if (!get_is_item_worn(item->getUUID())) + return true; + break; + default: + return true; + break; + } + return false; } bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return TRUE; - } - if(item) - { - if(item->getType() == mType) return TRUE; - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return TRUE; + } + if(item) + { + if(item->getType() == mType) return TRUE; + } + return FALSE; } bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return FALSE; - } - if(item) - { - if(item->getType() == mType) return FALSE; - else return TRUE; - } - return TRUE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return FALSE; + } + if(item) + { + if(item->getType() == mType) return FALSE; + else return TRUE; + } + return TRUE; } bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) return TRUE; - } - if(item) - { - if(item->getActualType() == mType) return TRUE; - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) return TRUE; + } + if(item) + { + if(item->getActualType() == mType) return TRUE; + } + return FALSE; } bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -2597,133 +2597,133 @@ bool LLAssetIDAndTypeMatches::operator()(LLInventoryCategory* cat, LLInventoryIt bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - LLViewerInventoryItem *vitem = dynamic_cast(item); - if (!vitem) return false; - return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); + LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem) return false; + return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); } bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if(mType == LLAssetType::AT_CATEGORY) - { - if(cat) - { - return TRUE; - } - } - if(item) - { - if(item->getType() == mType) - { - LLPermissions perm = item->getPermissions(); - if ((perm.getMaskBase() & mPerm) == mPerm) - { - return TRUE; - } - } - } - return FALSE; + if(mType == LLAssetType::AT_CATEGORY) + { + if(cat) + { + return TRUE; + } + } + if(item) + { + if(item->getType() == mType) + { + LLPermissions perm = item->getPermissions(); + if ((perm.getMaskBase() & mPerm) == mPerm) + { + return TRUE; + } + } + } + return FALSE; } bool LLBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (!item->getCreatorUUID().isNull()) - && (item->getCreatorUUID() != gAgent.getID())) - { - return true; - } - } - return false; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (!item->getCreatorUUID().isNull()) + && (item->getCreatorUUID() != gAgent.getID())) + { + return true; + } + } + return false; } bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (item->getCreatorUUID().notNull()) - && (item->getCreatorUUID() != gAgent.getID())) - { - mSeen.insert(item->getCreatorUUID()); - return true; - } - } - return false; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (item->getCreatorUUID().notNull()) + && (item->getCreatorUUID() != gAgent.getID())) + { + mSeen.insert(item->getCreatorUUID()); + return true; + } + } + return false; } bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((LLAssetType::AT_CALLINGCARD == item->getType()) - && (item->getCreatorUUID() == mBuddyID)) - { - return TRUE; - } - } - return FALSE; + if(item) + { + if((LLAssetType::AT_CALLINGCARD == item->getType()) + && (item->getCreatorUUID() == mBuddyID)) + { + return TRUE; + } + } + return FALSE; } bool LLNameCategoryCollector::operator()( - LLInventoryCategory* cat, LLInventoryItem* item) + LLInventoryCategory* cat, LLInventoryItem* item) { - if(cat) - { - if (!LLStringUtil::compareInsensitive(mName, cat->getName())) - { - return true; - } - } - return false; + if(cat) + { + if (!LLStringUtil::compareInsensitive(mName, cat->getName())) + { + return true; + } + } + return false; } bool LLNameItemCollector::operator()( - LLInventoryCategory* cat, LLInventoryItem* item) + LLInventoryCategory* cat, LLInventoryItem* item) { - if(item) - { - if (!LLStringUtil::compareInsensitive(mName, item->getName())) - { - return true; - } - } - return false; + if(item) + { + if (!LLStringUtil::compareInsensitive(mName, item->getName())) + { + return true; + } + } + return false; } bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - // Valid COF items are: - // - links to wearables (body parts or clothing) - // - links to attachments - // - links to gestures - // - links to ensemble folders - LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); - if (linked_item) - { - LLAssetType::EType type = linked_item->getType(); - return (type == LLAssetType::AT_CLOTHING || - type == LLAssetType::AT_BODYPART || - type == LLAssetType::AT_GESTURE || - type == LLAssetType::AT_OBJECT); - } - else - { - LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); - // BAP remove AT_NONE support after ensembles are fully working? - return (linked_category && - ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || - (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); - } + LLInventoryItem* item) +{ + // Valid COF items are: + // - links to wearables (body parts or clothing) + // - links to attachments + // - links to gestures + // - links to ensemble folders + LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); + if (linked_item) + { + LLAssetType::EType type = linked_item->getType(); + return (type == LLAssetType::AT_CLOTHING || + type == LLAssetType::AT_BODYPART || + type == LLAssetType::AT_GESTURE || + type == LLAssetType::AT_OBJECT); + } + else + { + LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); + // BAP remove AT_NONE support after ensembles are fully working? + return (linked_category && + ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || + (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); + } } bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat, @@ -2740,68 +2740,68 @@ bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat, } bool LLFindWearables::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item) - { - if((item->getType() == LLAssetType::AT_CLOTHING) - || (item->getType() == LLAssetType::AT_BODYPART)) - { - return TRUE; - } - } - return FALSE; + if(item) + { + if((item->getType() == LLAssetType::AT_CLOTHING) + || (item->getType() == LLAssetType::AT_BODYPART)) + { + return TRUE; + } + } + return FALSE; } LLFindWearablesEx::LLFindWearablesEx(bool is_worn, bool include_body_parts) -: mIsWorn(is_worn) -, mIncludeBodyParts(include_body_parts) +: mIsWorn(is_worn) +, mIncludeBodyParts(include_body_parts) {} bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - LLViewerInventoryItem *vitem = dynamic_cast(item); - if (!vitem) return false; + LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem) return false; - // Skip non-wearables. - if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) - { - return false; - } + // Skip non-wearables. + if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) + { + return false; + } - // Skip body parts if requested. - if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) - { - return false; - } + // Skip body parts if requested. + if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) + { + return false; + } - // Skip broken links. - if (vitem->getIsBrokenLink()) - { - return false; - } + // Skip broken links. + if (vitem->getIsBrokenLink()) + { + return false; + } - return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; + return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; } bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if (!item) return false; - if (item->getType() != LLAssetType::AT_CLOTHING && - item->getType() != LLAssetType::AT_BODYPART) - { - return false; - } + if (!item) return false; + if (item->getType() != LLAssetType::AT_CLOTHING && + item->getType() != LLAssetType::AT_BODYPART) + { + return false; + } - LLViewerInventoryItem *vitem = dynamic_cast(item); - if (!vitem || vitem->getWearableType() != mWearableType) return false; + LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem || vitem->getWearableType() != mWearableType) return false; - return true; + return true; } void LLFindWearablesOfType::setType(LLWearableType::EType type) { - mWearableType = type; + mWearableType = type; } bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -2811,141 +2811,141 @@ bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - if (item) - { - return !get_is_item_removable(&gInventory, item->getUUID()); - } - if (cat) - { - return !get_is_category_removable(&gInventory, cat->getUUID()); - } + if (item) + { + return !get_is_item_removable(&gInventory, item->getUUID()); + } + if (cat) + { + return !get_is_category_removable(&gInventory, cat->getUUID()); + } - LL_WARNS() << "Not a category and not an item?" << LL_ENDL; - return false; + LL_WARNS() << "Not a category and not an item?" << LL_ENDL; + return false; } ///---------------------------------------------------------------------------- -/// LLAssetIDMatches +/// LLAssetIDMatches ///---------------------------------------------------------------------------- bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - return (item && item->getAssetUUID() == mAssetID); + return (item && item->getAssetUUID() == mAssetID); } ///---------------------------------------------------------------------------- -/// LLLinkedItemIDMatches +/// LLLinkedItemIDMatches ///---------------------------------------------------------------------------- bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - return (item && - (item->getIsLinkType()) && - (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. + return (item && + (item->getIsLinkType()) && + (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. } void LLSaveFolderState::setApply(BOOL apply) { - mApply = apply; - // before generating new list of open folders, clear the old one - if(!apply) - { - clearOpenFolders(); - } + mApply = apply; + // before generating new list of open folders, clear the old one + if(!apply) + { + clearOpenFolders(); + } } void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getViewModelItem(); - if(!bridge) return; - - if(mApply) - { - // we're applying the open state - LLUUID id(bridge->getUUID()); - if(mOpenFolders.find(id) != mOpenFolders.end()) - { - if (!folder->isOpen()) - { - folder->setOpen(TRUE); - } - } - else - { - // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected() && folder->isOpen()) - { - folder->setOpen(FALSE); - } - } - } - else - { - // we're recording state at this point - if(folder->isOpen()) - { - mOpenFolders.insert(bridge->getUUID()); - } - } + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getViewModelItem(); + if(!bridge) return; + + if(mApply) + { + // we're applying the open state + LLUUID id(bridge->getUUID()); + if(mOpenFolders.find(id) != mOpenFolders.end()) + { + if (!folder->isOpen()) + { + folder->setOpen(TRUE); + } + } + else + { + // keep selected filter in its current state, this is less jarring to user + if (!folder->isSelected() && folder->isOpen()) + { + folder->setOpen(FALSE); + } + } + } + else + { + // we're recording state at this point + if(folder->isOpen()) + { + mOpenFolders.insert(bridge->getUUID()); + } + } } void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) { - if (item->passedFilter()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (item->passedFilter()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) { - if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - // if this folder didn't pass the filter, and none of its descendants did - else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter()) - { - folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); - } + if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + // if this folder didn't pass the filter, and none of its descendants did + else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter()) + { + folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); + } } void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) { - if (item->passedFilter() && !mItemSelected) - { - item->getRoot()->setSelection(item, FALSE, FALSE); - if (item->getParentFolder()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - mItemSelected = TRUE; - } + if (item->passedFilter() && !mItemSelected) + { + item->getRoot()->setSelection(item, FALSE, FALSE); + if (item->getParentFolder()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + mItemSelected = TRUE; + } } void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) { - // Skip if folder or item already found, if not filtered or if no parent (root folder is not selectable) - if (!mFolderSelected && !mItemSelected && folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) - { - folder->getRoot()->setSelection(folder, FALSE, FALSE); - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - mFolderSelected = TRUE; - } + // Skip if folder or item already found, if not filtered or if no parent (root folder is not selectable) + if (!mFolderSelected && !mItemSelected && folder->LLFolderViewItem::passedFilter() && folder->getParentFolder()) + { + folder->getRoot()->setSelection(folder, FALSE, FALSE); + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + mFolderSelected = TRUE; + } } void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) { - if (item->getParentFolder() && item->isSelected()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (item->getParentFolder() && item->isSelected()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) { - if (folder->getParentFolder() && folder->isSelected()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } + if (folder->getParentFolder() && folder->isSelected()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } } // Callback for doToSelected if DAMA required... @@ -2975,34 +2975,34 @@ void LLInventoryAction::callback_copySelected(const LLSD& notification, const LL // case returns their corresponding uuids. bool get_selection_object_uuids(LLFolderView *root, uuid_vec_t& ids) { - uuid_vec_t results; - S32 non_object = 0; - LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); - for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) - { - LLObjectBridge *view_model = dynamic_cast((*it)->getViewModelItem()); - - if(view_model && view_model->getUUID().notNull()) - { - results.push_back(view_model->getUUID()); - } - else - { - non_object++; - } - } - if (non_object == 0) - { - ids = results; - return true; - } - return false; + uuid_vec_t results; + S32 non_object = 0; + LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); + for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + LLObjectBridge *view_model = dynamic_cast((*it)->getViewModelItem()); + + if(view_model && view_model->getUUID().notNull()) + { + results.push_back(view_model->getUUID()); + } + else + { + non_object++; + } + } + if (non_object == 0) + { + ids = results; + return true; + } + return false; } void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm) { - std::set selected_items = root->getSelectionList(); + std::set selected_items = root->getSelectionList(); if (selected_items.empty() && action != "wear" && action != "wear_add" @@ -3020,9 +3020,9 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } - + // Prompt the user and check for authorization for some marketplace active listing edits - if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) + if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) { std::set::iterator set_iter = selected_items.begin(); LLFolderViewModelItemInventory * viewModel = NULL; @@ -3079,138 +3079,138 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } } - + // Keep track of the marketplace folders that will need update of their status/name after the operation is performed buildMarketplaceFolders(root); - - if ("rename" == action) - { - root->startRenamingSelectedItem(); + + if ("rename" == action) + { + root->startRenamingSelectedItem(); // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - return; - } - - if ("delete" == action) - { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - bool marketplacelistings_item = false; - LLAllDescendentsPassedFilter f; - for (std::set::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) - { - if (LLFolderViewFolder* folder = dynamic_cast(*it)) - { - folder->applyFunctorRecursively(f); - } - LLFolderViewModelItemInventory * viewModel = dynamic_cast((*it)->getViewModelItem()); - if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) - { - marketplacelistings_item = true; - break; - } - } - // Fall through to the generic confirmation if the user choose to ignore the specialized one - if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) - { - LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); - } - else - { - if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session - { - LLNotifications::instance().setIgnored("DeleteItems", false); - sDeleteConfirmationDisplayed = true; - } - - LLSD args; - args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); - LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); - } + return; + } + + if ("delete" == action) + { + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + bool marketplacelistings_item = false; + LLAllDescendentsPassedFilter f; + for (std::set::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) + { + if (LLFolderViewFolder* folder = dynamic_cast(*it)) + { + folder->applyFunctorRecursively(f); + } + LLFolderViewModelItemInventory * viewModel = dynamic_cast((*it)->getViewModelItem()); + if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) + { + marketplacelistings_item = true; + break; + } + } + // Fall through to the generic confirmation if the user choose to ignore the specialized one + if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) + { + LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } + else + { + if (!sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session + { + LLNotifications::instance().setIgnored("DeleteItems", false); + sDeleteConfirmationDisplayed = true; + } + + LLSD args; + args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); + LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } // Note: marketplace listings will be updated in the callback if delete confirmed - return; - } - if (("copy" == action) || ("cut" == action)) - { - // Clear the clipboard before we start adding things on it - LLClipboard::instance().reset(); - } - if ("replace_links" == action) - { - LLSD params; - if (root->getSelectedCount() == 1) - { - LLFolderViewItem* folder_item = root->getSelectedItems().front(); - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); - - if (bridge) - { - LLInventoryObject* obj = bridge->getInventoryObject(); - if (obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getActualType() != LLAssetType::AT_LINK_FOLDER) - { - params = LLSD(obj->getUUID()); - } - } - } - LLFloaterReg::showInstance("linkreplace", params); - return; - } - - static const std::string change_folder_string = "change_folder_type_"; - if (action.length() > change_folder_string.length() && - (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) - { - LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); - LLFolderViewModelItemInventory* inventory_item = static_cast(root->getViewModelItem()); - LLViewerInventoryCategory *cat = model->getCategory(inventory_item->getUUID()); - if (!cat) return; - cat->changeType(new_folder_type); + return; + } + if (("copy" == action) || ("cut" == action)) + { + // Clear the clipboard before we start adding things on it + LLClipboard::instance().reset(); + } + if ("replace_links" == action) + { + LLSD params; + if (root->getSelectedCount() == 1) + { + LLFolderViewItem* folder_item = root->getSelectedItems().front(); + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); + + if (bridge) + { + LLInventoryObject* obj = bridge->getInventoryObject(); + if (obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getActualType() != LLAssetType::AT_LINK_FOLDER) + { + params = LLSD(obj->getUUID()); + } + } + } + LLFloaterReg::showInstance("linkreplace", params); + return; + } + + static const std::string change_folder_string = "change_folder_type_"; + if (action.length() > change_folder_string.length() && + (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) + { + LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); + LLFolderViewModelItemInventory* inventory_item = static_cast(root->getViewModelItem()); + LLViewerInventoryCategory *cat = model->getCategory(inventory_item->getUUID()); + if (!cat) return; + cat->changeType(new_folder_type); // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - return; - } - - - LLMultiPreview* multi_previewp = NULL; - LLMultiItemProperties* multi_itempropertiesp = nullptr; - - if (("task_open" == action || "open" == action) && selected_items.size() > 1) - { - bool open_multi_preview = true; - - if ("open" == action) - { - for (std::set::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) - { - LLFolderViewItem* folder_item = *set_iter; - if (folder_item) - { - LLInvFVBridge* bridge = dynamic_cast(folder_item->getViewModelItem()); - if (!bridge || !bridge->isMultiPreviewAllowed()) - { - open_multi_preview = false; - break; - } - } - } - } - - if (open_multi_preview) - { - multi_previewp = new LLMultiPreview(); - gFloaterView->addChild(multi_previewp); - - LLFloater::setFloaterHost(multi_previewp); - } - - } - else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) - { - multi_itempropertiesp = new LLMultiItemProperties("item_properties"); - gFloaterView->addChild(multi_itempropertiesp); - LLFloater::setFloaterHost(multi_itempropertiesp); - } - - std::set selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); + return; + } + + + LLMultiPreview* multi_previewp = NULL; + LLMultiItemProperties* multi_itempropertiesp = nullptr; + + if (("task_open" == action || "open" == action) && selected_items.size() > 1) + { + bool open_multi_preview = true; + + if ("open" == action) + { + for (std::set::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewItem* folder_item = *set_iter; + if (folder_item) + { + LLInvFVBridge* bridge = dynamic_cast(folder_item->getViewModelItem()); + if (!bridge || !bridge->isMultiPreviewAllowed()) + { + open_multi_preview = false; + break; + } + } + } + } + + if (open_multi_preview) + { + multi_previewp = new LLMultiPreview(); + gFloaterView->addChild(multi_previewp); + + LLFloater::setFloaterHost(multi_previewp); + } + + } + else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) + { + multi_itempropertiesp = new LLMultiItemProperties("item_properties"); + gFloaterView->addChild(multi_itempropertiesp); + LLFloater::setFloaterHost(multi_itempropertiesp); + } + + std::set selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); // copy list of applicable items into a vector for bulk handling uuid_vec_t ids; @@ -3307,10 +3307,10 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root return; } } - + LLSD args; args["DESC"] = LLTrans::getString("New Folder"); - + LLNotificationsUtil::add("CreateSubfolder", args, LLSD(), [ids](const LLSD& notification, const LLSD& response) { @@ -3358,22 +3358,22 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); - - LLFloater::setFloaterHost(NULL); - if (multi_previewp) - { - multi_previewp->openFloater(LLSD()); - } - else if (multi_itempropertiesp) - { - multi_itempropertiesp->openFloater(LLSD()); - } + + LLFloater::setFloaterHost(NULL); + if (multi_previewp) + { + multi_previewp->openFloater(LLSD()); + } + else if (multi_itempropertiesp) + { + multi_itempropertiesp->openFloater(LLSD()); + } } void LLInventoryAction::saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model) { gSavedSettings.setString("TextureSaveLocation", filenames[0]); - + LLMultiPreview* multi_previewp = new LLMultiPreview(); gFloaterView->addChild(multi_previewp); @@ -3381,7 +3381,7 @@ void LLInventoryAction::saveMultipleTextures(const std::vector& fil std::map tex_names_map; std::set::iterator set_iter; - + for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) { LLFolderViewItem* folder_item = *set_iter; @@ -3390,10 +3390,10 @@ void LLInventoryAction::saveMultipleTextures(const std::vector& fil if(!bridge) continue; std::string tex_name = bridge->getName(); - if(!tex_names_map.insert(std::pair(tex_name, 0)).second) - { + if(!tex_names_map.insert(std::pair(tex_name, 0)).second) + { tex_names_map[tex_name]++; - bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); + bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); } bridge->performAction(model, "save_selected_as"); } @@ -3430,18 +3430,18 @@ void LLInventoryAction::removeItemFromDND(LLFolderView* root) void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0 && !root.isDead() && !root.get()->isDead()) - { - LLFolderView* folder_root = root.get(); - //Need to remove item from DND before item is removed from root folder view - //because once removed from root folder view the item is no longer a selected item - removeItemFromDND(folder_root); - folder_root->removeSelectedItems(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0 && !root.isDead() && !root.get()->isDead()) + { + LLFolderView* folder_root = root.get(); + //Need to remove item from DND before item is removed from root folder view + //because once removed from root folder view the item is no longer a selected item + removeItemFromDND(folder_root); + folder_root->removeSelectedItems(); - // Update the marketplace listings that have been affected by the operation - updateMarketplaceFolders(); - } + // Update the marketplace listings that have been affected by the operation + updateMarketplaceFolders(); + } } void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) @@ -3457,7 +3457,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.isNull()) { - return; + return; } std::set selected_items = root->getSelectionList(); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index edc83147f2..8edb51b5a8 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -1,4 +1,4 @@ -/** +/** * @file llinventoryfunctions.h * @brief Miscellaneous inventory-related functions and classes * class definition @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -184,10 +184,10 @@ private: class LLInventoryCollectFunctor { public: - virtual ~LLInventoryCollectFunctor(){}; - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; + virtual ~LLInventoryCollectFunctor(){}; + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; - static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); + static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -200,12 +200,12 @@ class LLViewerInventoryItem; class LLAssetIDMatches : public LLInventoryCollectFunctor { public: - LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} - virtual ~LLAssetIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - + LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} + virtual ~LLAssetIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + protected: - LLUUID mAssetID; + LLUUID mAssetID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -217,12 +217,12 @@ protected: class LLLinkedItemIDMatches : public LLInventoryCollectFunctor { public: - LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} - virtual ~LLLinkedItemIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - + LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} + virtual ~LLLinkedItemIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + protected: - LLUUID mBaseItemID; + LLUUID mBaseItemID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -235,12 +235,12 @@ protected: class LLIsType : public LLInventoryCollectFunctor { public: - LLIsType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -252,12 +252,12 @@ protected: class LLIsNotType : public LLInventoryCollectFunctor { public: - LLIsNotType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsNotType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsNotType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsNotType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -271,12 +271,12 @@ protected: class LLIsOfAssetType : public LLInventoryCollectFunctor { public: - LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsOfAssetType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsOfAssetType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; + LLAssetType::EType mType; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -304,23 +304,23 @@ protected: class LLIsValidItemLink : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; class LLIsTypeWithPermissions : public LLInventoryCollectFunctor { public: - LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) - : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} - virtual ~LLIsTypeWithPermissions() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) + : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} + virtual ~LLIsTypeWithPermissions() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLAssetType::EType mType; - PermissionBit mPerm; - LLUUID mAgentID; - LLUUID mGroupID; + LLAssetType::EType mType; + PermissionBit mPerm; + LLUUID mAgentID; + LLUUID mGroupID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -332,10 +332,10 @@ protected: class LLBuddyCollector : public LLInventoryCollectFunctor { public: - LLBuddyCollector() {} - virtual ~LLBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLBuddyCollector() {} + virtual ~LLBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -347,13 +347,13 @@ public: class LLUniqueBuddyCollector : public LLInventoryCollectFunctor { public: - LLUniqueBuddyCollector() {} - virtual ~LLUniqueBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLUniqueBuddyCollector() {} + virtual ~LLUniqueBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::set mSeen; + std::set mSeen; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -365,12 +365,12 @@ protected: class LLParticularBuddyCollector : public LLInventoryCollectFunctor { public: - LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} - virtual ~LLParticularBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} + virtual ~LLParticularBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - LLUUID mBuddyID; + LLUUID mBuddyID; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -381,12 +381,12 @@ protected: class LLNameCategoryCollector : public LLInventoryCollectFunctor { public: - LLNameCategoryCollector(const std::string& name) : mName(name) {} - virtual ~LLNameCategoryCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLNameCategoryCollector(const std::string& name) : mName(name) {} + virtual ~LLNameCategoryCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::string mName; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -397,12 +397,12 @@ protected: class LLNameItemCollector : public LLInventoryCollectFunctor { public: - LLNameItemCollector(const std::string& name) : mName(name) {} - virtual ~LLNameItemCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLNameItemCollector(const std::string& name) : mName(name) {} + virtual ~LLNameItemCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); protected: - std::string mName; + std::string mName; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -413,11 +413,11 @@ protected: class LLFindCOFValidItems : public LLInventoryCollectFunctor { public: - LLFindCOFValidItems() {} - virtual ~LLFindCOFValidItems() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - + LLFindCOFValidItems() {} + virtual ~LLFindCOFValidItems() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -440,23 +440,23 @@ public: class LLFindByMask : public LLInventoryCollectFunctor { public: - LLFindByMask(U64 mask) - : mFilterMask(mask) - {} + LLFindByMask(U64 mask) + : mFilterMask(mask) + {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - //converting an inventory type to a bitmap filter mask - if(item && (mFilterMask & (1LL << item->getInventoryType())) ) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + //converting an inventory type to a bitmap filter mask + if(item && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } - return false; - } + return false; + } private: - U64 mFilterMask; + U64 mFilterMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -467,27 +467,27 @@ private: class LLFindNonLinksByMask : public LLInventoryCollectFunctor { public: - LLFindNonLinksByMask(U64 mask) - : mFilterMask(mask) - {} + LLFindNonLinksByMask(U64 mask) + : mFilterMask(mask) + {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) - { - return true; - } + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } - return false; - } + return false; + } - void setFilterMask(U64 mask) - { - mFilterMask = mask; - } + void setFilterMask(U64 mask) + { + mFilterMask = mask; + } private: - U64 mFilterMask; + U64 mFilterMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -498,10 +498,10 @@ private: class LLFindWearables : public LLInventoryCollectFunctor { public: - LLFindWearables() {} - virtual ~LLFindWearables() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); + LLFindWearables() {} + virtual ~LLFindWearables() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -512,24 +512,24 @@ public: class LLFindWearablesEx : public LLInventoryCollectFunctor { public: - LLFindWearablesEx(bool is_worn, bool include_body_parts = true); - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + LLFindWearablesEx(bool is_worn, bool include_body_parts = true); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); private: - bool mIncludeBodyParts; - bool mIsWorn; + bool mIncludeBodyParts; + bool mIsWorn; }; //Inventory collect functor collecting wearables of a specific wearable type class LLFindWearablesOfType : public LLInventoryCollectFunctor { public: - LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} - virtual ~LLFindWearablesOfType() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - void setType(LLWearableType::EType type); + LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {} + virtual ~LLFindWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + void setType(LLWearableType::EType type); private: - LLWearableType::EType mWearableType; + LLWearableType::EType mWearableType; }; class LLIsTextureType : public LLInventoryCollectFunctor @@ -545,33 +545,33 @@ public: class LLFindActualWearablesOfType : public LLFindWearablesOfType { public: - LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} - virtual ~LLFindActualWearablesOfType() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if (item && item->getIsLinkType()) return false; - return LLFindWearablesOfType::operator()(cat, item); - } + LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {} + virtual ~LLFindActualWearablesOfType() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLFindWearablesOfType::operator()(cat, item); + } }; /* Filters out items of a particular asset type */ class LLIsTypeActual : public LLIsType { public: - LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} - virtual ~LLIsTypeActual() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - if (item && item->getIsLinkType()) return false; - return LLIsType::operator()(cat, item); - } + LLIsTypeActual(LLAssetType::EType type) : LLIsType(type) {} + virtual ~LLIsTypeActual() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (item && item->getIsLinkType()) return false; + return LLIsType::operator()(cat, item); + } }; // Collect non-removable folders and items. class LLFindNonRemovableObjects : public LLInventoryCollectFunctor { public: - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); }; /** Inventory Collector Functions @@ -585,27 +585,27 @@ class LLFolderView; class LLInventoryState { public: - // HACK: Until we can route this info through the instant message hierarchy - static BOOL sWearNewClothing; - static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction + // HACK: Until we can route this info through the instant message hierarchy + static BOOL sWearNewClothing; + static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction }; struct LLInventoryAction { - static void doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm = TRUE); - static void callback_doToSelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); - static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); - static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root); - static void removeItemFromDND(LLFolderView* root); + static void doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm = TRUE); + static void callback_doToSelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); + static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); + static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root); + static void removeItemFromDND(LLFolderView* root); static void saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model); static bool sDeleteConfirmationDisplayed; private: - static void buildMarketplaceFolders(LLFolderView* root); - static void updateMarketplaceFolders(); - static std::list sMarketplaceFolders; // Marketplace folders that will need update once the action is completed + static void buildMarketplaceFolders(LLFolderView* root); + static void updateMarketplaceFolders(); + static std::list sMarketplaceFolders; // Marketplace folders that will need update once the action is completed }; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 3a930684a4..6408d4eaf6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llinventorymodel.cpp * @brief Implementation of the inventory model used to track agent inventory. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, 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$ */ @@ -50,7 +50,7 @@ #include "llwindow.h" #include "llviewercontrol.h" #include "llviewernetwork.h" -#include "llpreview.h" +#include "llpreview.h" #include "llviewergenericmessage.h" #include "llviewermessage.h" #include "llviewerfoldertype.h" @@ -94,49 +94,49 @@ static const char * const LOG_INV("Inventory"); struct InventoryIDPtrLess { - bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const - { - return (i1->getUUID() < i2->getUUID()); - } + bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const + { + return (i1->getUUID() < i2->getUUID()); + } }; -class LLCanCache : public LLInventoryCollectFunctor +class LLCanCache : public LLInventoryCollectFunctor { public: - LLCanCache(LLInventoryModel* model) : mModel(model) {} - virtual ~LLCanCache() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + LLCanCache(LLInventoryModel* model) : mModel(model) {} + virtual ~LLCanCache() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); protected: - LLInventoryModel* mModel; - std::set mCachedCatIDs; + LLInventoryModel* mModel; + std::set mCachedCatIDs; }; bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - bool rv = false; - if(item) - { - if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) - { - rv = true; - } - } - else if(cat) - { - // HACK: downcast - LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; - if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = c->getDescendentCount(); - S32 descendents_actual = c->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - mCachedCatIDs.insert(c->getUUID()); - rv = true; - } - } - } - return rv; + bool rv = false; + if(item) + { + if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) + { + rv = true; + } + } + else if(cat) + { + // HACK: downcast + LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; + if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + S32 descendents_server = c->getDescendentCount(); + S32 descendents_actual = c->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + mCachedCatIDs.insert(c->getUUID()); + rv = true; + } + } + } + return rv; } struct InventoryCallbackInfo @@ -364,7 +364,7 @@ LLInventoryValidationInfo::LLInventoryValidationInfo() void LLInventoryValidationInfo::toOstream(std::ostream& os) const { - os << "mFatalErrorCount " << mFatalErrorCount + os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount << " mLoopCount " << mLoopCount << " mOrphanedCount " << mOrphanedCount; @@ -373,52 +373,52 @@ void LLInventoryValidationInfo::toOstream(std::ostream& os) const std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) { - v.toOstream(os); - return os; + v.toOstream(os); + return os; } void LLInventoryValidationInfo::asLLSD(LLSD& sd) const { - sd["fatal_error_count"] = mFatalErrorCount; + sd["fatal_error_count"] = mFatalErrorCount; sd["loop_count"] = mLoopCount; sd["orphaned_count"] = mOrphanedCount; - sd["initialized"] = mInitialized; - sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); - sd["fatal_no_root_folder"] = mFatalNoRootFolder; - sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder; - sd["fatal_qa_debug_mode"] = mFatalQADebugMode; - - sd["warning_count"] = mWarningCount; - if (mWarningCount>0) - { - sd["warnings"] = LLSD::emptyArray(); - for (auto const& it : mWarnings) - { - S32 val =LLSD::Integer(it.second); - if (val>0) - { - sd["warnings"][it.first] = val; - } - } - } - if (mMissingRequiredSystemFolders.size()>0) - { - sd["missing_system_folders"] = LLSD::emptyArray(); - for(auto ft: mMissingRequiredSystemFolders) - { - sd["missing_system_folders"].append(LLFolderType::lookup(ft)); - } - } - sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); - if (mDuplicateRequiredSystemFolders.size()>0) - { - sd["duplicate_system_folders"] = LLSD::emptyArray(); - for(auto ft: mDuplicateRequiredSystemFolders) - { - sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); - } - } - + sd["initialized"] = mInitialized; + sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); + sd["fatal_no_root_folder"] = mFatalNoRootFolder; + sd["fatal_no_library_root_folder"] = mFatalNoLibraryRootFolder; + sd["fatal_qa_debug_mode"] = mFatalQADebugMode; + + sd["warning_count"] = mWarningCount; + if (mWarningCount>0) + { + sd["warnings"] = LLSD::emptyArray(); + for (auto const& it : mWarnings) + { + S32 val =LLSD::Integer(it.second); + if (val>0) + { + sd["warnings"][it.first] = val; + } + } + } + if (mMissingRequiredSystemFolders.size()>0) + { + sd["missing_system_folders"] = LLSD::emptyArray(); + for(auto ft: mMissingRequiredSystemFolders) + { + sd["missing_system_folders"].append(LLFolderType::lookup(ft)); + } + } + sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); + if (mDuplicateRequiredSystemFolders.size()>0) + { + sd["duplicate_system_folders"] = LLSD::emptyArray(); + for(auto ft: mDuplicateRequiredSystemFolders) + { + sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); + } + } + } ///---------------------------------------------------------------------------- @@ -431,117 +431,117 @@ LLInventoryModel gInventory; // Default constructor LLInventoryModel::LLInventoryModel() : // These are now ordered, keep them that way. - mBacklinkMMap(), - mIsAgentInvUsable(false), - mRootFolderID(), - mLibraryRootFolderID(), - mLibraryOwnerID(), - mCategoryMap(), - mItemMap(), - mParentChildCategoryTree(), - mParentChildItemTree(), - mLastItem(NULL), - mIsNotifyObservers(FALSE), - mModifyMask(LLInventoryObserver::ALL), - mChangedItemIDs(), + mBacklinkMMap(), + mIsAgentInvUsable(false), + mRootFolderID(), + mLibraryRootFolderID(), + mLibraryOwnerID(), + mCategoryMap(), + mItemMap(), + mParentChildCategoryTree(), + mParentChildItemTree(), + mLastItem(NULL), + mIsNotifyObservers(FALSE), + mModifyMask(LLInventoryObserver::ALL), + mChangedItemIDs(), mBulkFecthCallbackSlot(), - mObservers(), - mHttpRequestFG(NULL), - mHttpRequestBG(NULL), - mHttpOptions(), - mHttpHeaders(), - mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mCategoryLock(), - mItemLock(), - mValidationInfo(new LLInventoryValidationInfo) + mObservers(), + mHttpRequestFG(NULL), + mHttpRequestBG(NULL), + mHttpOptions(), + mHttpHeaders(), + mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mCategoryLock(), + mItemLock(), + mValidationInfo(new LLInventoryValidationInfo) {} // Destroys the object LLInventoryModel::~LLInventoryModel() { - cleanupInventory(); + cleanupInventory(); } void LLInventoryModel::cleanupInventory() { - empty(); - // Deleting one observer might erase others from the list, so always pop off the front - while (!mObservers.empty()) - { - observer_list_t::iterator iter = mObservers.begin(); - LLInventoryObserver* observer = *iter; - mObservers.erase(iter); - delete observer; - } + empty(); + // Deleting one observer might erase others from the list, so always pop off the front + while (!mObservers.empty()) + { + observer_list_t::iterator iter = mObservers.begin(); + LLInventoryObserver* observer = *iter; + mObservers.erase(iter); + delete observer; + } if (mBulkFecthCallbackSlot.connected()) { mBulkFecthCallbackSlot.disconnect(); } - mObservers.clear(); + mObservers.clear(); - // Run down HTTP transport + // Run down HTTP transport mHttpHeaders.reset(); mHttpOptions.reset(); - delete mHttpRequestFG; - mHttpRequestFG = NULL; - delete mHttpRequestBG; - mHttpRequestBG = NULL; + delete mHttpRequestFG; + mHttpRequestFG = NULL; + delete mHttpRequestBG; + mHttpRequestBG = NULL; } // This is a convenience function to check if one object has a parent // chain up to the category specified by UUID. BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, - const LLUUID& cat_id) const + const LLUUID& cat_id) const { - if (obj_id == cat_id) return TRUE; - - const LLInventoryObject* obj = getObject(obj_id); - while(obj) - { - const LLUUID& parent_id = obj->getParentUUID(); - if( parent_id.isNull() ) - { - return FALSE; - } - if(parent_id == cat_id) - { - return TRUE; - } - // Since we're scanning up the parents, we only need to check - // in the category list. - obj = getCategory(parent_id); - } - return FALSE; + if (obj_id == cat_id) return TRUE; + + const LLInventoryObject* obj = getObject(obj_id); + while(obj) + { + const LLUUID& parent_id = obj->getParentUUID(); + if( parent_id.isNull() ) + { + return FALSE; + } + if(parent_id == cat_id) + { + return TRUE; + } + // Since we're scanning up the parents, we only need to check + // in the category list. + obj = getCategory(parent_id); + } + return FALSE; } const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const { - const LLInventoryObject* obj = getObject(obj_id); - if(!obj) - { - LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; - return NULL; - } - // Search up the parent chain until we get to root or an acceptable folder. - // This assumes there are no cycles in the tree else we'll get a hang. - LLUUID parent_id = obj->getParentUUID(); - while (!parent_id.isNull()) - { - const LLViewerInventoryCategory *cat = getCategory(parent_id); - if (!cat) break; - const LLFolderType::EType folder_type = cat->getPreferredType(); - if (folder_type != LLFolderType::FT_NONE && - folder_type != LLFolderType::FT_ROOT_INVENTORY && - !LLFolderType::lookupIsEnsembleType(folder_type)) - { - return cat; - } - parent_id = cat->getParentUUID(); - } - return NULL; + const LLInventoryObject* obj = getObject(obj_id); + if(!obj) + { + LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; + return NULL; + } + // Search up the parent chain until we get to root or an acceptable folder. + // This assumes there are no cycles in the tree else we'll get a hang. + LLUUID parent_id = obj->getParentUUID(); + while (!parent_id.isNull()) + { + const LLViewerInventoryCategory *cat = getCategory(parent_id); + if (!cat) break; + const LLFolderType::EType folder_type = cat->getPreferredType(); + if (folder_type != LLFolderType::FT_NONE && + folder_type != LLFolderType::FT_ROOT_INVENTORY && + !LLFolderType::lookupIsEnsembleType(folder_type)) + { + return cat; + } + parent_id = cat->getParentUUID(); + } + return NULL; } // @@ -549,36 +549,36 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons // const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const { - if (master_parent_id == obj_id) - { - return NULL; - } - - const LLViewerInventoryCategory* current_cat = getCategory(obj_id); - - if (current_cat == NULL) - { - current_cat = getCategory(getObject(obj_id)->getParentUUID()); - } - - while (current_cat != NULL) - { - const LLUUID& current_parent_id = current_cat->getParentUUID(); - - if (current_parent_id == master_parent_id) - { - return current_cat; - } - - current_cat = getCategory(current_parent_id); - } - - return NULL; + if (master_parent_id == obj_id) + { + return NULL; + } + + const LLViewerInventoryCategory* current_cat = getCategory(obj_id); + + if (current_cat == NULL) + { + current_cat = getCategory(getObject(obj_id)->getParentUUID()); + } + + while (current_cat != NULL) + { + const LLUUID& current_parent_id = current_cat->getParentUUID(); + + if (current_parent_id == master_parent_id) + { + return current_cat; + } + + current_cat = getCategory(current_parent_id); + } + + return NULL; } LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const { - LLInventoryObject *object = getObject(object_id); + LLInventoryObject *object = getObject(object_id); if (!object) { LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL; @@ -596,73 +596,73 @@ LLInventoryModel::EAncestorResult LLInventoryModel::getObjectTopmostAncestor(con } object_ids.insert(parent_id); LLInventoryObject *parent_object = getObject(parent_id); - if (!parent_object) - { - LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; - return ANCESTOR_MISSING; - } - object = parent_object; - } - result = object->getUUID(); - return ANCESTOR_OK; + if (!parent_object) + { + LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; + return ANCESTOR_MISSING; + } + object = parent_object; + } + result = object->getUUID(); + return ANCESTOR_OK; } // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { - LLViewerInventoryCategory* cat = getCategory(id); - if (cat) - { - return cat; - } - LLViewerInventoryItem* item = getItem(id); - if (item) - { - return item; - } - return NULL; + LLViewerInventoryCategory* cat = getCategory(id); + if (cat) + { + return cat; + } + LLViewerInventoryItem* item = getItem(id); + if (item) + { + return item; + } + return NULL; } // Get the item by id. Returns NULL if not found. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const { - LLViewerInventoryItem* item = NULL; - if(mLastItem.notNull() && mLastItem->getUUID() == id) - { - item = mLastItem; - } - else - { - item_map_t::const_iterator iter = mItemMap.find(id); - if (iter != mItemMap.end()) - { - item = iter->second; - mLastItem = item; - } - } - return item; + LLViewerInventoryItem* item = NULL; + if(mLastItem.notNull() && mLastItem->getUUID() == id) + { + item = mLastItem; + } + else + { + item_map_t::const_iterator iter = mItemMap.find(id); + if (iter != mItemMap.end()) + { + item = iter->second; + mLastItem = item; + } + } + return item; } // Get the category by id. Returns NULL if not found LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const { - LLViewerInventoryCategory* category = NULL; - cat_map_t::const_iterator iter = mCategoryMap.find(id); - if (iter != mCategoryMap.end()) - { - category = iter->second; - } - return category; + LLViewerInventoryCategory* category = NULL; + cat_map_t::const_iterator iter = mCategoryMap.find(id); + if (iter != mCategoryMap.end()) + { + category = iter->second; + } + return category; } S32 LLInventoryModel::getItemCount() const { - return mItemMap.size(); + return mItemMap.size(); } S32 LLInventoryModel::getCategoryCount() const { - return mCategoryMap.size(); + return mCategoryMap.size(); } // Return the direct descendents of the id provided. The array @@ -671,11 +671,11 @@ S32 LLInventoryModel::getCategoryCount() const // may invalidate the internal state of the inventory. Set passed // in values to NULL if the call fails. void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, - cat_array_t*& categories, - item_array_t*& items) const + cat_array_t*& categories, + item_array_t*& items) const { - categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); - items = get_ptr_in_map(mParentChildItemTree, cat_id); + categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); + items = get_ptr_in_map(mParentChildItemTree, cat_id); } void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const @@ -684,10 +684,10 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& { for (LLViewerInventoryCategory* pFolder : *categoriesp) { - if (f(pFolder, nullptr)) - { - categories.push_back(pFolder); - } + if (f(pFolder, nullptr)) + { + categories.push_back(pFolder); + } } } @@ -695,56 +695,56 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& { for (LLViewerInventoryItem* pItem : *itemsp) { - if (f(nullptr, pItem)) - { - items.push_back(pItem); - } + if (f(nullptr, pItem)) + { + items.push_back(pItem); + } } } } LLInventoryModel::digest_t LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - getDirectDescendentsOf(cat_id,cat_array,item_array); - if (!item_array) - { - return LLUUID::null; - } - HBXXH128 item_name_hash; - for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); - iter != item_array->end(); - iter++) - { - const LLViewerInventoryItem *item = (*iter); - if (!item) - continue; - item_name_hash.update(item->getName()); - } - return item_name_hash.digest(); + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + getDirectDescendentsOf(cat_id,cat_array,item_array); + if (!item_array) + { + return LLUUID::null; + } + HBXXH128 item_name_hash; + for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); + iter != item_array->end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + if (!item) + continue; + item_name_hash.update(item->getName()); + } + return item_name_hash.digest(); } // SJB: Added version to lock the arrays to catch potential logic bugs void LLInventoryModel::lockDirectDescendentArrays(const LLUUID& cat_id, - cat_array_t*& categories, - item_array_t*& items) + cat_array_t*& categories, + item_array_t*& items) { - getDirectDescendentsOf(cat_id, categories, items); - if (categories) - { - mCategoryLock[cat_id] = true; - } - if (items) - { - mItemLock[cat_id] = true; - } + getDirectDescendentsOf(cat_id, categories, items); + if (categories) + { + mCategoryLock[cat_id] = true; + } + if (items) + { + mItemLock[cat_id] = true; + } } void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) { - mCategoryLock[cat_id] = false; - mItemLock[cat_id] = false; + mCategoryLock[cat_id] = false; + mItemLock[cat_id] = false; } void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::EType type) @@ -761,15 +761,15 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } // Iterate through those folders - for (std::vector::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) - { - LLUUID folder_id = (*folder_ids_it); - + for (std::vector::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) + { + LLUUID folder_id = (*folder_ids_it); + // Get the content of this folder cat_array_t* cats; item_array_t* items; getDirectDescendentsOf(folder_id, cats, items); - + // Move all items to the main folder // Note : we get the list of UUIDs and iterate on them instead of iterating directly on item_array_t // elements. This is because moving elements modify the maps and, consequently, invalidate iterators on them. @@ -809,7 +809,7 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } } remove_inventory_category(folder_id, NULL); - } + } } void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type) @@ -881,49 +881,49 @@ void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred } const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( - LLFolderType::EType preferred_type, - const LLUUID& root_id) const + LLFolderType::EType preferred_type, + const LLUUID& root_id) const { - LLUUID rv = LLUUID::null; - if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) - { - rv = root_id; - } - else if (root_id.notNull()) - { - cat_array_t* cats = NULL; - cats = get_ptr_in_map(mParentChildCategoryTree, root_id); - if(cats) - { - S32 count = cats->size(); - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* p_cat = cats->at(i); - if(p_cat && p_cat->getPreferredType() == preferred_type) - { - const LLUUID& folder_id = cats->at(i)->getUUID(); - if (rv.isNull() || folder_id < rv) - { - rv = folder_id; - } - } - } - } - } - - if(rv.isNull() + LLUUID rv = LLUUID::null; + if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) + { + rv = root_id; + } + else if (root_id.notNull()) + { + cat_array_t* cats = NULL; + cats = get_ptr_in_map(mParentChildCategoryTree, root_id); + if(cats) + { + S32 count = cats->size(); + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* p_cat = cats->at(i); + if(p_cat && p_cat->getPreferredType() == preferred_type) + { + const LLUUID& folder_id = cats->at(i)->getUUID(); + if (rv.isNull() || folder_id < rv) + { + rv = folder_id; + } + } + } + } + } + + if(rv.isNull() && root_id.notNull() && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS && preferred_type != LLFolderType::FT_OUTBOX) - { + { // if it does not exists, it should either be added // to createCommonSystemCategories or server should // have set it llassert(!isInventoryUsable()); LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type - << " but category does not exist" << LL_ENDL; - } - return rv; + << " but category does not exist" << LL_ENDL; + } + return rv; } // findCategoryUUIDForType() returns the uuid of the category that @@ -932,7 +932,7 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( // inventory category on the fly if one does not exist. const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); } const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const @@ -968,7 +968,7 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: default: break; } - + if (cat_id.isNull() || !getCategory(cat_id)) { cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID()); @@ -978,7 +978,7 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); } // Convenience function to create a new category. You could call @@ -986,56 +986,56 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp // version will take care of details like what the name should be // based on preferred type. void LLInventoryModel::createNewCategory(const LLUUID& parent_id, - LLFolderType::EType preferred_type, - const std::string& pname, - inventory_func_type callback, - const LLUUID& thumbnail_id) + LLFolderType::EType preferred_type, + const std::string& pname, + inventory_func_type callback, + const LLUUID& thumbnail_id) { - LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; - if (!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " - << preferred_type << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; + if (!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " + << preferred_type << LL_ENDL; if (callback) { callback(LLUUID::null); } - return; - } + return; + } - if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) - { - LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; + if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) + { + LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; if (callback) { callback(LLUUID::null); } - return; - } - - if (preferred_type != LLFolderType::FT_NONE) - { - // Ultimately this should only be done for non-singleton - // types. Requires back-end changes to guarantee that others - // already exist. - LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; - } - - std::string name = pname; - if (pname.empty()) - { - name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); - } - - if (AISAPI::isAvailable()) - { - LLSD new_inventory = LLSD::emptyMap(); - new_inventory["categories"] = LLSD::emptyArray(); - LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); + return; + } + + if (preferred_type != LLFolderType::FT_NONE) + { + // Ultimately this should only be done for non-singleton + // types. Requires back-end changes to guarantee that others + // already exist. + LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; + } + + std::string name = pname; + if (pname.empty()) + { + name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); + } + + if (AISAPI::isAvailable()) + { + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["categories"] = LLSD::emptyArray(); + LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); cat.setThumbnailUUID(thumbnail_id); - LLSD cat_sd = cat.asAISCreateCatLLSD(); - new_inventory["categories"].append(cat_sd); - AISAPI::CreateInventory( + LLSD cat_sd = cat.asAISCreateCatLLSD(); + new_inventory["categories"].append(cat_sd); + AISAPI::CreateInventory( parent_id, new_inventory, [this, callback, parent_id, preferred_type, name] (const LLUUID& new_category) @@ -1075,32 +1075,32 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, } }); return; - } - - LLViewerRegion* viewer_region = gAgent.getRegion(); - std::string url; - if ( viewer_region ) - url = viewer_region->getCapability("CreateInventoryCategory"); - - if (!url.empty()) - { - //Let's use the new capability. + } + + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty()) + { + //Let's use the new capability. LLUUID id; - id.generate(); - LLSD request, body; - body["folder_id"] = id; - body["parent_id"] = parent_id; - body["type"] = (LLSD::Integer) preferred_type; - body["name"] = name; - - request["message"] = "CreateInventoryCategory"; - request["payload"] = body; - - LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; + id.generate(); + LLSD request, body; + body["folder_id"] = id; + body["parent_id"] = parent_id; + body["type"] = (LLSD::Integer) preferred_type; + body["name"] = name; + + request["message"] = "CreateInventoryCategory"; + request["payload"] = body; + + LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); return; - } + } if (callback) { @@ -1115,7 +1115,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("createNewCategoryCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - + httpOpts->setWantHeaders(true); @@ -1213,36 +1213,36 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv // category has any immediate children meeting a condition, without // needing to recurse or build up any lists. bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, - LLInventoryCollectFunctor& filter) + LLInventoryCollectFunctor& filter) { - LLInventoryModel::cat_array_t *cats; - LLInventoryModel::item_array_t *items; - getDirectDescendentsOf(cat_id, cats, items); - if (cats) - { - for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); - it != cats->end(); ++it) - { - if (filter(*it,NULL)) - { - return true; - } - } - } - if (items) - { - for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); - it != items->end(); ++it) - { - if (filter(NULL,*it)) - { - return true; - } - } - } - return false; + LLInventoryModel::cat_array_t *cats; + LLInventoryModel::item_array_t *items; + getDirectDescendentsOf(cat_id, cats, items); + if (cats) + { + for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); + it != cats->end(); ++it) + { + if (filter(*it,NULL)) + { + return true; + } + } + } + if (items) + { + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); + it != items->end(); ++it) + { + if (filter(NULL,*it)) + { + return true; + } + } + } + return false; } - + // Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified by // id. There is no guaranteed order. Neither array will be erased @@ -1253,135 +1253,135 @@ bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, class LLAlwaysCollect : public LLInventoryCollectFunctor { public: - virtual ~LLAlwaysCollect() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - return TRUE; - } + virtual ~LLAlwaysCollect() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + return TRUE; + } }; void LLInventoryModel::collectDescendents(const LLUUID& id, - cat_array_t& cats, - item_array_t& items, - BOOL include_trash) + cat_array_t& cats, + item_array_t& items, + BOOL include_trash) { - LLAlwaysCollect always; - collectDescendentsIf(id, cats, items, include_trash, always); + LLAlwaysCollect always; + collectDescendentsIf(id, cats, items, include_trash, always); } void LLInventoryModel::collectDescendentsIf(const LLUUID& id, - cat_array_t& cats, - item_array_t& items, - BOOL include_trash, - LLInventoryCollectFunctor& add) + cat_array_t& cats, + item_array_t& items, + BOOL include_trash, + LLInventoryCollectFunctor& add) { - // Start with categories - if(!include_trash) - { - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(trash_id.notNull() && (trash_id == id)) - return; - } - cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); - if(cat_array) - { - S32 count = cat_array->size(); - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = cat_array->at(i); - if(add(cat,NULL)) - { - cats.push_back(cat); - } - collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); - } - } - - LLViewerInventoryItem* item = NULL; - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - - // Move onto items - if(item_array) - { - S32 count = item_array->size(); - for(S32 i = 0; i < count; ++i) - { - item = item_array->at(i); - if(add(NULL, item)) - { - items.push_back(item); - } - } - } + // Start with categories + if(!include_trash) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(trash_id.notNull() && (trash_id == id)) + return; + } + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if(cat_array) + { + S32 count = cat_array->size(); + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = cat_array->at(i); + if(add(cat,NULL)) + { + cats.push_back(cat); + } + collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); + } + } + + LLViewerInventoryItem* item = NULL; + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + // Move onto items + if(item_array) + { + S32 count = item_array->size(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->at(i); + if(add(NULL, item)) + { + items.push_back(item); + } + } + } } void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { - const LLInventoryObject *obj = getObject(object_id); - if (!obj || obj->getIsLinkType()) - return; - - LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); - for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) - { - LLViewerInventoryItem *linked_item = (*iter); - addChangedMask(mask, linked_item->getUUID()); - }; + const LLInventoryObject *obj = getObject(object_id); + if (!obj || obj->getIsLinkType()) + return; + + LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + addChangedMask(mask, linked_item->getUUID()); + }; } const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const { - const LLInventoryItem *item = gInventory.getItem(object_id); - if (!item) - { - return object_id; - } - - // Find the base item in case this a link (if it's not a link, - // this will just be inv_item_id) - return item->getLinkedUUID(); + const LLInventoryItem *item = gInventory.getItem(object_id); + if (!item) + { + return object_id; + } + + // Find the base item in case this a link (if it's not a link, + // this will just be inv_item_id) + return item->getLinkedUUID(); } LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) const { - return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; + return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; } LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id) { - // Get item list via collectDescendents (slow!) - item_array_t items; - const LLInventoryObject *obj = getObject(id); - // FIXME - should be as in next line, but this is causing a - // stack-smashing crash of cause TBD... check in the REBUILD code. - //if (obj && obj->getIsLinkType()) - if (!obj || obj->getIsLinkType()) - return items; - - std::pair range = mBacklinkMMap.equal_range(id); - for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) - { - LLViewerInventoryItem *item = getItem(it->second); - if (item) - { - items.push_back(item); - } - } - - return items; + // Get item list via collectDescendents (slow!) + item_array_t items; + const LLInventoryObject *obj = getObject(id); + // FIXME - should be as in next line, but this is causing a + // stack-smashing crash of cause TBD... check in the REBUILD code. + //if (obj && obj->getIsLinkType()) + if (!obj || obj->getIsLinkType()) + return items; + + std::pair range = mBacklinkMMap.equal_range(id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) + { + LLViewerInventoryItem *item = getItem(it->second); + if (item) + { + items.push_back(item); + } + } + + return items; } bool LLInventoryModel::isInventoryUsable() const { - bool result = false; - if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) - { - result = true; - } - return result; + bool result = false; + if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) + { + result = true; + } + return result; } // Calling this method with an inventory item will either change an @@ -1389,34 +1389,34 @@ bool LLInventoryModel::isInventoryUsable() const // current inventory. U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { - if(item->getUUID().isNull()) - { - return mask; - } - - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return mask; - } - - if (item->getType() == LLAssetType::AT_MESH) - { - return mask; - } - - LLPointer old_item = getItem(item->getUUID()); - LLPointer new_item; - if(old_item) - { - // We already have an old item, modify its values - new_item = old_item; - LLUUID old_parent_id = old_item->getParentUUID(); - LLUUID new_parent_id = item->getParentUUID(); - bool update_parent_on_server = false; - - if (new_parent_id.isNull() && !LLApp::isExiting()) - { + if(item->getUUID().isNull()) + { + return mask; + } + + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return mask; + } + + if (item->getType() == LLAssetType::AT_MESH) + { + return mask; + } + + LLPointer old_item = getItem(item->getUUID()); + LLPointer new_item; + if(old_item) + { + // We already have an old item, modify its values + new_item = old_item; + LLUUID old_parent_id = old_item->getParentUUID(); + LLUUID new_parent_id = item->getParentUUID(); + bool update_parent_on_server = false; + + if (new_parent_id.isNull() && !LLApp::isExiting()) + { if (old_parent_id.isNull()) { // Item with null parent will end in random location and then in Lost&Found, @@ -1438,359 +1438,359 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) new_parent_id = old_parent_id; update_parent_on_server = true; } - } - - if(old_parent_id != new_parent_id) - { - // need to update the parent-child tree - item_array_t* item_array; - item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); - if(item_array) - { - vector_replace_with_last(*item_array, old_item); - } - item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); - if(item_array) - { - if (update_parent_on_server) - { - LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); - gInventory.accountForUpdate(update); - } - item_array->push_back(old_item); - } - mask |= LLInventoryObserver::STRUCTURE; - } - if(old_item->getName() != item->getName()) - { - mask |= LLInventoryObserver::LABEL; - } + } + + if(old_parent_id != new_parent_id) + { + // need to update the parent-child tree + item_array_t* item_array; + item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); + if(item_array) + { + vector_replace_with_last(*item_array, old_item); + } + item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); + if(item_array) + { + if (update_parent_on_server) + { + LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); + gInventory.accountForUpdate(update); + } + item_array->push_back(old_item); + } + mask |= LLInventoryObserver::STRUCTURE; + } + if(old_item->getName() != item->getName()) + { + mask |= LLInventoryObserver::LABEL; + } if (old_item->getPermissions() != item->getPermissions()) { mask |= LLInventoryObserver::INTERNAL; } - old_item->copyViewerItem(item); - if (update_parent_on_server) - { - // Parent id at server is null, so update server even if item already is in the same folder - old_item->setParent(new_parent_id); - new_item->updateParentOnServer(FALSE); - } - mask |= LLInventoryObserver::INTERNAL; - } - else - { - // Simply add this item - new_item = new LLViewerInventoryItem(item); - addItem(new_item); - - if(item->getParentUUID().isNull()) - { - const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType())); - new_item->setParent(category_id); - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); - if( item_array ) - { - LLInventoryModel::LLCategoryUpdate update(category_id, 1); - gInventory.accountForUpdate(update); - - // *FIX: bit of a hack to call update server from here... - new_item->updateParentOnServer(FALSE); - item_array->push_back(new_item); - } - else - { - LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; - } - } - else - { - // *NOTE: The general scheme is that if every byte of the - // uuid is 0, except for the last one or two,the use the - // last two bytes of the parent id, and match that up - // against the type. For now, we're only worried about - // lost & found. - LLUUID parent_id = item->getParentUUID(); - if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID) - { - parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - new_item->setParent(parent_id); - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - } - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); - if(item_array) - { - item_array->push_back(new_item); - } - else - { - // Whoops! No such parent, make one. - LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " - << new_item->getName() << LL_ENDL; - parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - new_item->setParent(parent_id); - item_array = get_ptr_in_map(mParentChildItemTree, parent_id); - if(item_array) - { - LLInventoryModel::LLCategoryUpdate update(parent_id, 1); - gInventory.accountForUpdate(update); - // *FIX: bit of a hack to call update server from - // here... - new_item->updateParentOnServer(FALSE); - item_array->push_back(new_item); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - } - mask |= LLInventoryObserver::ADD; - } - if(new_item->getType() == LLAssetType::AT_CALLINGCARD) - { - mask |= LLInventoryObserver::CALLING_CARD; - // Handle user created calling cards. - // Target ID is stored in the description field of the card. - LLUUID id; - std::string desc = new_item->getDescription(); - BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); - if (isId) - { - // Valid UUID; set the item UUID and rename it - new_item->setCreator(id); - LLAvatarName av_name; - - if (LLAvatarNameCache::get(id, &av_name)) - { - new_item->rename(av_name.getUserName()); - mask |= LLInventoryObserver::LABEL; - } - else - { - // Fetch the current name - LLAvatarNameCache::get(id, - boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), - _1, _2)); - } - - } - } - else if (new_item->getType() == LLAssetType::AT_GESTURE) - { - mask |= LLInventoryObserver::GESTURE; - } - addChangedMask(mask, new_item->getUUID()); - return mask; + old_item->copyViewerItem(item); + if (update_parent_on_server) + { + // Parent id at server is null, so update server even if item already is in the same folder + old_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + } + mask |= LLInventoryObserver::INTERNAL; + } + else + { + // Simply add this item + new_item = new LLViewerInventoryItem(item); + addItem(new_item); + + if(item->getParentUUID().isNull()) + { + const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType())); + new_item->setParent(category_id); + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); + if( item_array ) + { + LLInventoryModel::LLCategoryUpdate update(category_id, 1); + gInventory.accountForUpdate(update); + + // *FIX: bit of a hack to call update server from here... + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); + } + else + { + LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; + } + } + else + { + // *NOTE: The general scheme is that if every byte of the + // uuid is 0, except for the last one or two,the use the + // last two bytes of the parent id, and match that up + // against the type. For now, we're only worried about + // lost & found. + LLUUID parent_id = item->getParentUUID(); + if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID) + { + parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + new_item->setParent(parent_id); + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + } + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); + if(item_array) + { + item_array->push_back(new_item); + } + else + { + // Whoops! No such parent, make one. + LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " + << new_item->getName() << LL_ENDL; + parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + new_item->setParent(parent_id); + item_array = get_ptr_in_map(mParentChildItemTree, parent_id); + if(item_array) + { + LLInventoryModel::LLCategoryUpdate update(parent_id, 1); + gInventory.accountForUpdate(update); + // *FIX: bit of a hack to call update server from + // here... + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + } + mask |= LLInventoryObserver::ADD; + } + if(new_item->getType() == LLAssetType::AT_CALLINGCARD) + { + mask |= LLInventoryObserver::CALLING_CARD; + // Handle user created calling cards. + // Target ID is stored in the description field of the card. + LLUUID id; + std::string desc = new_item->getDescription(); + BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); + if (isId) + { + // Valid UUID; set the item UUID and rename it + new_item->setCreator(id); + LLAvatarName av_name; + + if (LLAvatarNameCache::get(id, &av_name)) + { + new_item->rename(av_name.getUserName()); + mask |= LLInventoryObserver::LABEL; + } + else + { + // Fetch the current name + LLAvatarNameCache::get(id, + boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), + _1, _2)); + } + + } + } + else if (new_item->getType() == LLAssetType::AT_GESTURE) + { + mask |= LLInventoryObserver::GESTURE; + } + addChangedMask(mask, new_item->getUUID()); + return mask; } LLInventoryModel::cat_array_t* LLInventoryModel::getUnlockedCatArray(const LLUUID& id) { - cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); - if (cat_array) - { - llassert_always(mCategoryLock[id] == false); - } - return cat_array; + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if (cat_array) + { + llassert_always(mCategoryLock[id] == false); + } + return cat_array; } LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLUUID& id) { - item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); - if (item_array) - { - llassert_always(mItemLock[id] == false); - } - return item_array; + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + if (item_array) + { + llassert_always(mItemLock[id] == false); + } + return item_array; } // Calling this method with an inventory category will either change // an existing item with the matching id, or it will add the category. void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask) { - if(!cat || cat->getUUID().isNull()) - { - return; - } - - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return; - } - - LLPointer old_cat = getCategory(cat->getUUID()); - if(old_cat) - { - // We already have an old category, modify its values - LLUUID old_parent_id = old_cat->getParentUUID(); - LLUUID new_parent_id = cat->getParentUUID(); - if(old_parent_id != new_parent_id) - { - // need to update the parent-child tree - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(old_parent_id); - if(cat_array) - { - vector_replace_with_last(*cat_array, old_cat); - } - cat_array = getUnlockedCatArray(new_parent_id); - if(cat_array) - { - cat_array->push_back(old_cat); - } - mask |= LLInventoryObserver::STRUCTURE; + if(!cat || cat->getUUID().isNull()) + { + return; + } + + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return; + } + + LLPointer old_cat = getCategory(cat->getUUID()); + if(old_cat) + { + // We already have an old category, modify its values + LLUUID old_parent_id = old_cat->getParentUUID(); + LLUUID new_parent_id = cat->getParentUUID(); + if(old_parent_id != new_parent_id) + { + // need to update the parent-child tree + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(old_parent_id); + if(cat_array) + { + vector_replace_with_last(*cat_array, old_cat); + } + cat_array = getUnlockedCatArray(new_parent_id); + if(cat_array) + { + cat_array->push_back(old_cat); + } + mask |= LLInventoryObserver::STRUCTURE; mask |= LLInventoryObserver::INTERNAL; - } - if(old_cat->getName() != cat->getName()) - { - mask |= LLInventoryObserver::LABEL; - } + } + if(old_cat->getName() != cat->getName()) + { + mask |= LLInventoryObserver::LABEL; + } // Under marketplace, category labels are quite complex and need extra upate const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) { - mask |= LLInventoryObserver::LABEL; + mask |= LLInventoryObserver::LABEL; } old_cat->copyViewerCategory(cat); - addChangedMask(mask, cat->getUUID()); - } - else - { - // add this category - LLPointer new_cat = new LLViewerInventoryCategory(cat->getOwnerID()); - new_cat->copyViewerCategory(cat); - addCategory(new_cat); - - // make sure this category is correctly referenced by its parent. - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) - { - cat_array->push_back(new_cat); - } - - // make space in the tree for this category's children. - llassert_always(mCategoryLock[new_cat->getUUID()] == false); - llassert_always(mItemLock[new_cat->getUUID()] == false); - cat_array_t* catsp = new cat_array_t; - item_array_t* itemsp = new item_array_t; - mParentChildCategoryTree[new_cat->getUUID()] = catsp; - mParentChildItemTree[new_cat->getUUID()] = itemsp; - mask |= LLInventoryObserver::ADD; - addChangedMask(mask, cat->getUUID()); - } + addChangedMask(mask, cat->getUUID()); + } + else + { + // add this category + LLPointer new_cat = new LLViewerInventoryCategory(cat->getOwnerID()); + new_cat->copyViewerCategory(cat); + addCategory(new_cat); + + // make sure this category is correctly referenced by its parent. + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) + { + cat_array->push_back(new_cat); + } + + // make space in the tree for this category's children. + llassert_always(mCategoryLock[new_cat->getUUID()] == false); + llassert_always(mItemLock[new_cat->getUUID()] == false); + cat_array_t* catsp = new cat_array_t; + item_array_t* itemsp = new item_array_t; + mParentChildCategoryTree[new_cat->getUUID()] = catsp; + mParentChildItemTree[new_cat->getUUID()] = itemsp; + mask |= LLInventoryObserver::ADD; + addChangedMask(mask, cat->getUUID()); + } } void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) { - LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; - if(!isInventoryUsable()) - { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; - return; - } - - if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) - { - LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " - << cat_id << LL_ENDL; - return; - } - LLPointer cat = getCategory(object_id); - if(cat && (cat->getParentUUID() != cat_id)) - { - LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) vector_replace_with_last(*cat_array, cat); - cat_array = getUnlockedCatArray(cat_id); - cat->setParent(cat_id); - if(cat_array) cat_array->push_back(cat); - addChangedMask(LLInventoryObserver::STRUCTURE, object_id); - return; - } - LLPointer item = getItem(object_id); - if(item && (item->getParentUUID() != cat_id)) - { - LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; - item_array_t* item_array; - item_array = getUnlockedItemArray(item->getParentUUID()); - if(item_array) vector_replace_with_last(*item_array, item); - item_array = getUnlockedItemArray(cat_id); - item->setParent(cat_id); - if(item_array) item_array->push_back(item); - addChangedMask(LLInventoryObserver::STRUCTURE, object_id); - return; - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; + if(!isInventoryUsable()) + { + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + return; + } + + if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) + { + LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " + << cat_id << LL_ENDL; + return; + } + LLPointer cat = getCategory(object_id); + if(cat && (cat->getParentUUID() != cat_id)) + { + LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; + cat_array_t* cat_array; + cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) vector_replace_with_last(*cat_array, cat); + cat_array = getUnlockedCatArray(cat_id); + cat->setParent(cat_id); + if(cat_array) cat_array->push_back(cat); + addChangedMask(LLInventoryObserver::STRUCTURE, object_id); + return; + } + LLPointer item = getItem(object_id); + if(item && (item->getParentUUID() != cat_id)) + { + LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; + item_array_t* item_array; + item_array = getUnlockedItemArray(item->getParentUUID()); + if(item_array) vector_replace_with_last(*item_array, item); + item_array = getUnlockedItemArray(cat_id); + item->setParent(cat_id); + if(item_array) item_array->push_back(item); + addChangedMask(LLInventoryObserver::STRUCTURE, object_id); + return; + } } // Migrated from llinventoryfunctions void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp) + const LLUUID& new_parent_id, + BOOL restamp) { - if (item->getParentUUID() == new_parent_id) - { - LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; - } - else - { - LL_INFOS(LOG_INV) << "Move item " << make_info(item) - << " from " << make_inventory_info(item->getParentUUID()) - << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(restamp); - updateItem(new_item); - notifyObservers(); - } + if (item->getParentUUID() == new_parent_id) + { + LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; + } + else + { + LL_INFOS(LOG_INV) << "Move item " << make_info(item) + << " from " << make_inventory_info(item->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(restamp); + updateItem(new_item); + notifyObservers(); + } } // Migrated from llinventoryfunctions void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp) + const LLUUID& new_parent_id, + BOOL restamp) { - if (!cat) - { - return; - } - - // Can't move a folder into a child of itself. - if (isObjectDescendentOf(new_parent_id, cat->getUUID())) - { - return; - } - - LL_INFOS(LOG_INV) << "Move category " << make_info(cat) - << " from " << make_inventory_info(cat->getParentUUID()) - << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - updateCategory(new_cat); - notifyObservers(); + if (!cat) + { + return; + } + + // Can't move a folder into a child of itself. + if (isObjectDescendentOf(new_parent_id, cat->getUUID())) + { + return; + } + + LL_INFOS(LOG_INV) << "Move category " << make_info(cat) + << " from " << make_inventory_info(cat->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent_id); + new_cat->updateParentOnServer(restamp); + updateCategory(new_cat); + notifyObservers(); } void LLInventoryModel::rebuildBrockenLinks() @@ -1817,262 +1817,262 @@ void LLInventoryModel::rebuildBrockenLinks() // Does not appear to be used currently. void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) { - U32 mask = LLInventoryObserver::NONE; - - LLPointer item = gInventory.getItem(item_id); - LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; - if(item) - { - for (LLSD::map_const_iterator it = updates.beginMap(); - it != updates.endMap(); ++it) - { - if (it->first == "name") - { - LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; - item->rename(it->second.asString()); - mask |= LLInventoryObserver::LABEL; - } - else if (it->first == "desc") - { - LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() - << " to " << it->second.asString() << LL_ENDL; - item->setDescription(it->second.asString()); - } - else - { - LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; - } - } - mask |= LLInventoryObserver::INTERNAL; - addChangedMask(mask, item->getUUID()); - if (update_parent_version) - { - // Descendent count is unchanged, but folder version incremented. - LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); - accountForUpdate(up); - } - notifyObservers(); // do we want to be able to make this optional? - } + U32 mask = LLInventoryObserver::NONE; + + LLPointer item = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; + if(item) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; + item->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else if (it->first == "desc") + { + LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() + << " to " << it->second.asString() << LL_ENDL; + item->setDescription(it->second.asString()); + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, item->getUUID()); + if (update_parent_version) + { + // Descendent count is unchanged, but folder version incremented. + LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); + accountForUpdate(up); + } + notifyObservers(); // do we want to be able to make this optional? + } } // Not used? void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) { - U32 mask = LLInventoryObserver::NONE; - - LLPointer cat = gInventory.getCategory(cat_id); - LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; - if(cat) - { - for (LLSD::map_const_iterator it = updates.beginMap(); - it != updates.endMap(); ++it) - { - if (it->first == "name") - { - LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; - cat->rename(it->second.asString()); - mask |= LLInventoryObserver::LABEL; - } - else - { - LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; - } - } - mask |= LLInventoryObserver::INTERNAL; - addChangedMask(mask, cat->getUUID()); - notifyObservers(); // do we want to be able to make this optional? - } + U32 mask = LLInventoryObserver::NONE; + + LLPointer cat = gInventory.getCategory(cat_id); + LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; + if(cat) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; + cat->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, cat->getUUID()); + notifyObservers(); // do we want to be able to make this optional? + } } // Update model after descendents have been purged. void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) { - LLPointer cat = getCategory(object_id); - if (cat.notNull()) - { - // do the cache accounting - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); - accountForUpdate(up); - } - - // we know that descendent count is 0, however since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); - - // unceremoniously remove anything we have locally stored. - LLInventoryModel::cat_array_t categories; - LLInventoryModel::item_array_t items; - collectDescendents(object_id, - categories, - items, - LLInventoryModel::INCLUDE_TRASH); - S32 count = items.size(); - - LLUUID uu_id; - for(S32 i = 0; i < count; ++i) - { - uu_id = items.at(i)->getUUID(); - - // This check prevents the deletion of a previously deleted item. - // This is necessary because deletion is not done in a hierarchical - // order. The current item may have been already deleted as a child - // of its deleted parent. - if (getItem(uu_id)) - { - deleteObject(uu_id, fix_broken_links); - } - } - - count = categories.size(); - // Slightly kludgy way to make sure categories are removed - // only after their child categories have gone away. - - // FIXME: Would probably make more sense to have this whole - // descendent-clearing thing be a post-order recursive - // function to get the leaf-up behavior automatically. - S32 deleted_count; - S32 total_deleted_count = 0; - do - { - deleted_count = 0; - for(S32 i = 0; i < count; ++i) - { - uu_id = categories.at(i)->getUUID(); - if (getCategory(uu_id)) - { - cat_array_t* cat_list = getUnlockedCatArray(uu_id); - if (!cat_list || (cat_list->size() == 0)) - { - deleteObject(uu_id, fix_broken_links); - deleted_count++; - } - } - } - total_deleted_count += deleted_count; - } - while (deleted_count > 0); - if (total_deleted_count != count) - { - LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " - << total_deleted_count << " expected " << count << LL_ENDL; - } - //gInventory.validate(); - } + LLPointer cat = getCategory(object_id); + if (cat.notNull()) + { + // do the cache accounting + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); + accountForUpdate(up); + } + + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // unceremoniously remove anything we have locally stored. + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + collectDescendents(object_id, + categories, + items, + LLInventoryModel::INCLUDE_TRASH); + S32 count = items.size(); + + LLUUID uu_id; + for(S32 i = 0; i < count; ++i) + { + uu_id = items.at(i)->getUUID(); + + // This check prevents the deletion of a previously deleted item. + // This is necessary because deletion is not done in a hierarchical + // order. The current item may have been already deleted as a child + // of its deleted parent. + if (getItem(uu_id)) + { + deleteObject(uu_id, fix_broken_links); + } + } + + count = categories.size(); + // Slightly kludgy way to make sure categories are removed + // only after their child categories have gone away. + + // FIXME: Would probably make more sense to have this whole + // descendent-clearing thing be a post-order recursive + // function to get the leaf-up behavior automatically. + S32 deleted_count; + S32 total_deleted_count = 0; + do + { + deleted_count = 0; + for(S32 i = 0; i < count; ++i) + { + uu_id = categories.at(i)->getUUID(); + if (getCategory(uu_id)) + { + cat_array_t* cat_list = getUnlockedCatArray(uu_id); + if (!cat_list || (cat_list->size() == 0)) + { + deleteObject(uu_id, fix_broken_links); + deleted_count++; + } + } + } + total_deleted_count += deleted_count; + } + while (deleted_count > 0); + if (total_deleted_count != count) + { + LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " + << total_deleted_count << " expected " << count << LL_ENDL; + } + //gInventory.validate(); + } } // Update model after an item is confirmed as removed from // server. Works for categories or items. void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) { - LLPointer obj = getObject(object_id); - if(obj) - { - if (getCategory(object_id)) - { - // For category, need to delete/update all children first. - onDescendentsPurgedFromServer(object_id, fix_broken_links); - } - - - // From item/cat removeFromServer() - if (update_parent_version) - { - LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); - accountForUpdate(up); - } - - // From purgeObject() - LLViewerInventoryItem *item = getItem(object_id); - if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) - { - LLPreview::hide(object_id, TRUE); - } - deleteObject(object_id, fix_broken_links, do_notify_observers); - } + LLPointer obj = getObject(object_id); + if(obj) + { + if (getCategory(object_id)) + { + // For category, need to delete/update all children first. + onDescendentsPurgedFromServer(object_id, fix_broken_links); + } + + + // From item/cat removeFromServer() + if (update_parent_version) + { + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + } + + // From purgeObject() + LLViewerInventoryItem *item = getItem(object_id); + if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) + { + LLPreview::hide(object_id, TRUE); + } + deleteObject(object_id, fix_broken_links, do_notify_observers); + } } // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers) { - LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; - LLPointer obj = getObject(id); - if (!obj) - { - LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; - return; - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; + LLPointer obj = getObject(id); + if (!obj) + { + LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; + return; + } //collect the links before removing the item from mItemMap LLInventoryModel::item_array_t links = collectLinksTo(id); - - LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; - mLastItem = NULL; - LLUUID parent_id = obj->getParentUUID(); - mCategoryMap.erase(id); - mItemMap.erase(id); - //mInventory.erase(id); - item_array_t* item_list = getUnlockedItemArray(parent_id); - if(item_list) - { - LLPointer item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); - vector_replace_with_last(*item_list, item); - } - cat_array_t* cat_list = getUnlockedCatArray(parent_id); - if(cat_list) - { - LLPointer cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); - vector_replace_with_last(*cat_list, cat); - } - + + LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; + mLastItem = NULL; + LLUUID parent_id = obj->getParentUUID(); + mCategoryMap.erase(id); + mItemMap.erase(id); + //mInventory.erase(id); + item_array_t* item_list = getUnlockedItemArray(parent_id); + if(item_list) + { + LLPointer item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); + vector_replace_with_last(*item_list, item); + } + cat_array_t* cat_list = getUnlockedCatArray(parent_id); + if(cat_list) + { + LLPointer cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); + vector_replace_with_last(*cat_list, cat); + } + // Note : We need to tell the inventory observers that those things are going to be deleted *before* the tree is cleared or they won't know what to delete (in views and view models) - addChangedMask(LLInventoryObserver::REMOVE, id); - gInventory.notifyObservers(); - - item_list = getUnlockedItemArray(id); - if(item_list) - { - if (item_list->size()) - { - LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; - } - delete item_list; - mParentChildItemTree.erase(id); - } - cat_list = getUnlockedCatArray(id); - if(cat_list) - { - if (cat_list->size()) - { - LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; - } - delete cat_list; - mParentChildCategoryTree.erase(id); - } - addChangedMask(LLInventoryObserver::REMOVE, id); - - bool is_link_type = obj->getIsLinkType(); - if (is_link_type) - { - removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); - } - - // Can't have links to links, so there's no need for this update - // if the item removed is a link. Can also skip if source of the - // update is getting broken link info separately. - if (fix_broken_links && !is_link_type) - { + addChangedMask(LLInventoryObserver::REMOVE, id); + gInventory.notifyObservers(); + + item_list = getUnlockedItemArray(id); + if(item_list) + { + if (item_list->size()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; + } + delete item_list; + mParentChildItemTree.erase(id); + } + cat_list = getUnlockedCatArray(id); + if(cat_list) + { + if (cat_list->size()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; + } + delete cat_list; + mParentChildCategoryTree.erase(id); + } + addChangedMask(LLInventoryObserver::REMOVE, id); + + bool is_link_type = obj->getIsLinkType(); + if (is_link_type) + { + removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); + } + + // Can't have links to links, so there's no need for this update + // if the item removed is a link. Can also skip if source of the + // update is getting broken link info separately. + if (fix_broken_links && !is_link_type) + { rebuildLinkItems(links); - } - obj = nullptr; // delete obj - if (do_notify_observers) - { - notifyObservers(); - } + } + obj = nullptr; // delete obj + if (do_notify_observers) + { + notifyObservers(); + } } void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items) @@ -2100,23 +2100,23 @@ void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items) // remove it. void LLInventoryModel::addObserver(LLInventoryObserver* observer) { - mObservers.insert(observer); + mObservers.insert(observer); } - + void LLInventoryModel::removeObserver(LLInventoryObserver* observer) { - mObservers.erase(observer); + mObservers.erase(observer); } BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const { - return mObservers.find(observer) != mObservers.end(); + return mObservers.find(observer) != mObservers.end(); } void LLInventoryModel::idleNotifyObservers() { - // *FIX: Think I want this conditional or moved elsewhere... - handleResponses(true); + // *FIX: Think I want this conditional or moved elsewhere... + handleResponses(true); if (mLinksRebuildList.size() > 0) { @@ -2131,78 +2131,78 @@ void LLInventoryModel::idleNotifyObservers() mLinksRebuildList.clear(); notifyObservers(); } - - if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) - { - return; - } - notifyObservers(); + + if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) + { + return; + } + notifyObservers(); } // Call this method when it's time to update everyone on a new state. void LLInventoryModel::notifyObservers() { - if (mIsNotifyObservers) - { - // Within notifyObservers, something called notifyObservers - // again. This type of recursion is unsafe because it causes items to be - // processed twice, and this can easily lead to infinite loops. - LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; - return; - } - - mIsNotifyObservers = TRUE; - for (observer_list_t::iterator iter = mObservers.begin(); - iter != mObservers.end(); ) - { - LLInventoryObserver* observer = *iter; - observer->changed(mModifyMask); - - // safe way to increment since changed may delete entries! (@!##%@!@&*!) - iter = mObservers.upper_bound(observer); - } - - // If there were any changes that arrived during notifyObservers, - // shedule them for next loop - mModifyMask = mModifyMaskBacklog; - mChangedItemIDs.clear(); - mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); - mAddedItemIDs.clear(); - mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); - - mModifyMaskBacklog = LLInventoryObserver::NONE; - mChangedItemIDsBacklog.clear(); - mAddedItemIDsBacklog.clear(); - - mIsNotifyObservers = FALSE; + if (mIsNotifyObservers) + { + // Within notifyObservers, something called notifyObservers + // again. This type of recursion is unsafe because it causes items to be + // processed twice, and this can easily lead to infinite loops. + LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; + return; + } + + mIsNotifyObservers = TRUE; + for (observer_list_t::iterator iter = mObservers.begin(); + iter != mObservers.end(); ) + { + LLInventoryObserver* observer = *iter; + observer->changed(mModifyMask); + + // safe way to increment since changed may delete entries! (@!##%@!@&*!) + iter = mObservers.upper_bound(observer); + } + + // If there were any changes that arrived during notifyObservers, + // shedule them for next loop + mModifyMask = mModifyMaskBacklog; + mChangedItemIDs.clear(); + mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); + mAddedItemIDs.clear(); + mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); + + mModifyMaskBacklog = LLInventoryObserver::NONE; + mChangedItemIDsBacklog.clear(); + mAddedItemIDsBacklog.clear(); + + mIsNotifyObservers = FALSE; } // store flag for change // and id of object change applies to -void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) -{ - if (mIsNotifyObservers) - { - // Something marked an item for change within a call to notifyObservers - // (which is in the process of processing the list of items marked for change). - // This means the change will have to be processed later. - // It's preferable for this not to happen, but it's not an issue unless code - // specifically wants to notifyObservers immediately (changes won't happen untill later) - LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; - LLViewerInventoryItem *item = getItem(referent); - if (item) - { - LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; - } - else - { - LLViewerInventoryCategory *cat = getCategory(referent); - if (cat) - { - LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; - } - } - } +void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) +{ + if (mIsNotifyObservers) + { + // Something marked an item for change within a call to notifyObservers + // (which is in the process of processing the list of items marked for change). + // This means the change will have to be processed later. + // It's preferable for this not to happen, but it's not an issue unless code + // specifically wants to notifyObservers immediately (changes won't happen untill later) + LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; + LLViewerInventoryItem *item = getItem(referent); + if (item) + { + LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; + } + else + { + LLViewerInventoryCategory *cat = getCategory(referent); + if (cat) + { + LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; + } + } + } if (mIsNotifyObservers) { @@ -2227,7 +2227,7 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } if (needs_update) - { + { if (mIsNotifyObservers) { mChangedItemIDsBacklog.insert(referent); @@ -2256,42 +2256,42 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) mAddedItemIDs.insert(referent); } } - - // Update all linked items. Starting with just LABEL because I'm - // not sure what else might need to be accounted for this. - if (mask & LLInventoryObserver::LABEL) - { - addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); - } - } + + // Update all linked items. Starting with just LABEL because I'm + // not sure what else might need to be accounted for this. + if (mask & LLInventoryObserver::LABEL) + { + addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); + } + } } bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const { - if(folder_id.isNull()) - { - LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; - return false; - } - LLViewerInventoryCategory* cat = getCategory(folder_id); - if(!cat) - { - LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " - << folder_id << LL_ENDL; - return false; - } - //S32 known_descendents = 0; - ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); - //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); - //if(categories) - //{ - // known_descendents += categories->size(); - //} - //if(items) - //{ - // known_descendents += items->size(); - //} - return cat->fetch(); + if(folder_id.isNull()) + { + LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; + return false; + } + LLViewerInventoryCategory* cat = getCategory(folder_id); + if(!cat) + { + LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " + << folder_id << LL_ENDL; + return false; + } + //S32 known_descendents = 0; + ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); + //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); + //if(categories) + //{ + // known_descendents += categories->size(); + //} + //if(items) + //{ + // known_descendents += items->size(); + //} + return cat->fetch(); } //static @@ -2318,138 +2318,138 @@ std::string LLInventoryModel::getInvCacheAddres(const LLUUID& owner_id) } void LLInventoryModel::cache( - const LLUUID& parent_folder_id, - const LLUUID& agent_id) + const LLUUID& parent_folder_id, + const LLUUID& agent_id) { - LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id - << LL_ENDL; - LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); - if(!root_cat) return; - cat_array_t categories; - categories.push_back(root_cat); - item_array_t items; - - LLCanCache can_cache(this); - can_cache(root_cat, NULL); - collectDescendentsIf( - parent_folder_id, - categories, - items, - INCLUDE_TRASH, - can_cache); + LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id + << LL_ENDL; + LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); + if(!root_cat) return; + cat_array_t categories; + categories.push_back(root_cat); + item_array_t items; + + LLCanCache can_cache(this); + can_cache(root_cat, NULL); + collectDescendentsIf( + parent_folder_id, + categories, + items, + INCLUDE_TRASH, + can_cache); // Use temporary file to avoid potential conflicts with other // instances (even a 'read only' instance unzips into a file) std::string temp_file = gDirUtilp->getTempFilename(); - saveToFile(temp_file, categories, items); + saveToFile(temp_file, categories, items); std::string gzip_filename = getInvCacheAddres(agent_id); - gzip_filename.append(".gz"); - if(gzip_file(temp_file, gzip_filename)) - { - LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; - LLFile::remove(temp_file); - } - else - { - LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; - } + gzip_filename.append(".gz"); + if(gzip_file(temp_file, gzip_filename)) + { + LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; + LLFile::remove(temp_file); + } + else + { + LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; + } } void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) { - //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; - if(category) - { - // We aren't displaying the Meshes folder - if (category->mPreferredType == LLFolderType::FT_MESH) - { - return; - } - - // try to localize default names first. See EXT-8319, EXT-7051. - category->localizeName(); - - // Insert category uniquely into the map - mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one - //mInventory[category->getUUID()] = category; - } + //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; + if(category) + { + // We aren't displaying the Meshes folder + if (category->mPreferredType == LLFolderType::FT_MESH) + { + return; + } + + // try to localize default names first. See EXT-8319, EXT-7051. + category->localizeName(); + + // Insert category uniquely into the map + mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one + //mInventory[category->getUUID()] = category; + } } bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const { - std::pair range; - range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - if (it->second == link_id) - { - return true; - } - } - return false; + std::pair range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + if (it->second == link_id) + { + return true; + } + } + return false; } void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - if (!hasBacklinkInfo(link_id, target_id)) - { - mBacklinkMMap.insert(std::make_pair(target_id, link_id)); - } + if (!hasBacklinkInfo(link_id, target_id)) + { + mBacklinkMMap.insert(std::make_pair(target_id, link_id)); + } } void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - std::pair range; - range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::iterator it = range.first; it != range.second; ) - { - if (it->second == link_id) - { - backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. - ++it; - mBacklinkMMap.erase(delete_it); - } - else - { - ++it; - } - } + std::pair range; + range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ) + { + if (it->second == link_id) + { + backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. + ++it; + mBacklinkMMap.erase(delete_it); + } + else + { + ++it; + } + } } void LLInventoryModel::addItem(LLViewerInventoryItem* item) { - llassert(item); - if(item) - { - if (item->getType() <= LLAssetType::AT_NONE) - { - LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; - return; - } - - if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) - { - if (item->getType() >= LLAssetType::AT_COUNT) - { - // Not yet supported. - LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; - } - else - { - LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; - } - } - - // This condition means that we tried to add a link without the baseobj being in memory. - // The item will show up as a broken link. - if (item->getIsBrokenLink()) - { + llassert(item); + if(item) + { + if (item->getType() <= LLAssetType::AT_NONE) + { + LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; + return; + } + + if (LLAssetType::lookup(item->getType()) == LLAssetType::BADLOOKUP) + { + if (item->getType() >= LLAssetType::AT_COUNT) + { + // Not yet supported. + LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + } + + // This condition means that we tried to add a link without the baseobj being in memory. + // The item will show up as a broken link. + if (item->getIsBrokenLink()) + { if (item->getAssetUUID().notNull() && LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive()) { @@ -2485,7 +2485,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; } - } + } if (!mPossiblyBrockenLinks.empty()) { // check if we are waiting for this item @@ -2496,705 +2496,705 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) mPossiblyBrockenLinks.erase(iter); } } - if (item->getIsLinkType()) - { - // Add back-link from linked-to UUID. - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - addBacklinkInfo(link_id, target_id); - } - mItemMap[item->getUUID()] = item; - } + if (item->getIsLinkType()) + { + // Add back-link from linked-to UUID. + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + addBacklinkInfo(link_id, target_id); + } + mItemMap[item->getUUID()] = item; + } } // Empty the entire contents void LLInventoryModel::empty() { -// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; - std::for_each( - mParentChildCategoryTree.begin(), - mParentChildCategoryTree.end(), - DeletePairedPointer()); - mParentChildCategoryTree.clear(); - std::for_each( - mParentChildItemTree.begin(), - mParentChildItemTree.end(), - DeletePairedPointer()); - mParentChildItemTree.clear(); - mBacklinkMMap.clear(); // forget all backlink information. - mCategoryMap.clear(); // remove all references (should delete entries) - mItemMap.clear(); // remove all references (should delete entries) - mLastItem = NULL; - //mInventory.clear(); +// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; + std::for_each( + mParentChildCategoryTree.begin(), + mParentChildCategoryTree.end(), + DeletePairedPointer()); + mParentChildCategoryTree.clear(); + std::for_each( + mParentChildItemTree.begin(), + mParentChildItemTree.end(), + DeletePairedPointer()); + mParentChildItemTree.clear(); + mBacklinkMMap.clear(); // forget all backlink information. + mCategoryMap.clear(); // remove all references (should delete entries) + mItemMap.clear(); // remove all references (should delete entries) + mLastItem = NULL; + //mInventory.clear(); } void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const { - LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); - if(cat) - { - S32 version = cat->getVersion(); - if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = cat->getDescendentCount(); - S32 descendents_actual = cat->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - descendents_actual += update.mDescendentDelta; - cat->setDescendentCount(descendents_actual); - cat->setVersion(++version); - LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " - << version << " with " << descendents_actual - << " descendents." << LL_ENDL; - } - else - { - // Error condition, this means that the category did not register that - // it got new descendents (perhaps because it is still being loaded) - // which means its descendent count will be wrong. - LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" - << version << " due to mismatched descendent count: server == " - << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; - } - } - else - { - LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" - << version << ")" << LL_ENDL; - } - } - else - { - LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; - } + LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); + if(cat) + { + S32 version = cat->getVersion(); + if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + descendents_actual += update.mDescendentDelta; + cat->setDescendentCount(descendents_actual); + cat->setVersion(++version); + LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " + << version << " with " << descendents_actual + << " descendents." << LL_ENDL; + } + else + { + // Error condition, this means that the category did not register that + // it got new descendents (perhaps because it is still being loaded) + // which means its descendent count will be wrong. + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" + << version << " due to mismatched descendent count: server == " + << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; + } + } + else + { + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" + << version << ")" << LL_ENDL; + } + } + else + { + LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; + } } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_list_t& update) + const LLInventoryModel::update_list_t& update) { - update_list_t::const_iterator it = update.begin(); - update_list_t::const_iterator end = update.end(); - for(; it != end; ++it) - { - accountForUpdate(*it); - } + update_list_t::const_iterator it = update.begin(); + update_list_t::const_iterator end = update.end(); + for(; it != end; ++it) + { + accountForUpdate(*it); + } } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_map_t& update) + const LLInventoryModel::update_map_t& update) { - LLCategoryUpdate up; - update_map_t::const_iterator it = update.begin(); - update_map_t::const_iterator end = update.end(); - for(; it != end; ++it) - { - up.mCategoryID = (*it).first; - up.mDescendentDelta = (*it).second.mValue; - accountForUpdate(up); - } + LLCategoryUpdate up; + update_map_t::const_iterator it = update.begin(); + update_map_t::const_iterator end = update.end(); + for(; it != end; ++it) + { + up.mCategoryID = (*it).first; + up.mDescendentDelta = (*it).second.mValue; + accountForUpdate(up); + } } LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( - const LLUUID& cat_id) const + const LLUUID& cat_id) const { - LLViewerInventoryCategory* cat = getCategory(cat_id); - if(!cat) return CHILDREN_NO; - if(cat->getDescendentCount() > 0) - { - return CHILDREN_YES; - } - if(cat->getDescendentCount() == 0) - { - return CHILDREN_NO; - } - if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) - || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) - { - return CHILDREN_MAYBE; - } - - // Shouldn't have to run this, but who knows. - parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) - { - return CHILDREN_YES; - } - parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); - if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) - { - return CHILDREN_YES; - } - - return CHILDREN_NO; + LLViewerInventoryCategory* cat = getCategory(cat_id); + if(!cat) return CHILDREN_NO; + if(cat->getDescendentCount() > 0) + { + return CHILDREN_YES; + } + if(cat->getDescendentCount() == 0) + { + return CHILDREN_NO; + } + if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + return CHILDREN_MAYBE; + } + + // Shouldn't have to run this, but who knows. + parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); + if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) + { + return CHILDREN_YES; + } + parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); + if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) + { + return CHILDREN_YES; + } + + return CHILDREN_NO; } bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const { - LLViewerInventoryCategory* cat = getCategory(cat_id); - if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) - { - S32 descendents_server = cat->getDescendentCount(); - S32 descendents_actual = cat->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - return true; - } - } - return false; -} - + LLViewerInventoryCategory* cat = getCategory(cat_id); + if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) + { + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if(descendents_server == descendents_actual) + { + return true; + } + } + return false; +} + bool LLInventoryModel::loadSkeleton( - const LLSD& options, - const LLUUID& owner_id) + const LLSD& options, + const LLUUID& owner_id) { LL_PROFILE_ZONE_SCOPED; - LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; - - typedef std::set, InventoryIDPtrLess> cat_set_t; - cat_set_t temp_cats; - bool rv = true; - - for(LLSD::array_const_iterator it = options.beginArray(), - end = options.endArray(); it != end; ++it) - { - LLSD name = (*it)["name"]; - LLSD folder_id = (*it)["folder_id"]; - LLSD parent_id = (*it)["parent_id"]; - LLSD version = (*it)["version"]; - if(name.isDefined() - && folder_id.isDefined() - && parent_id.isDefined() - && version.isDefined() - && folder_id.asUUID().notNull() // if an id is null, it locks the viewer. - ) - { - LLPointer cat = new LLViewerInventoryCategory(owner_id); - cat->rename(name.asString()); - cat->setUUID(folder_id.asUUID()); - cat->setParent(parent_id.asUUID()); - - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLSD type_default = (*it)["type_default"]; - if(type_default.isDefined()) + LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; + + typedef std::set, InventoryIDPtrLess> cat_set_t; + cat_set_t temp_cats; + bool rv = true; + + for(LLSD::array_const_iterator it = options.beginArray(), + end = options.endArray(); it != end; ++it) + { + LLSD name = (*it)["name"]; + LLSD folder_id = (*it)["folder_id"]; + LLSD parent_id = (*it)["parent_id"]; + LLSD version = (*it)["version"]; + if(name.isDefined() + && folder_id.isDefined() + && parent_id.isDefined() + && version.isDefined() + && folder_id.asUUID().notNull() // if an id is null, it locks the viewer. + ) + { + LLPointer cat = new LLViewerInventoryCategory(owner_id); + cat->rename(name.asString()); + cat->setUUID(folder_id.asUUID()); + cat->setParent(parent_id.asUUID()); + + LLFolderType::EType preferred_type = LLFolderType::FT_NONE; + LLSD type_default = (*it)["type_default"]; + if(type_default.isDefined()) { - preferred_type = (LLFolderType::EType)type_default.asInteger(); + preferred_type = (LLFolderType::EType)type_default.asInteger(); } cat->setPreferredType(preferred_type); - cat->setVersion(version.asInteger()); + cat->setVersion(version.asInteger()); temp_cats.insert(cat); - } - else - { - LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; rv = false; - } - } - - S32 cached_category_count = 0; - S32 cached_item_count = 0; - if(!temp_cats.empty()) - { - update_map_t child_counts; - cat_array_t categories; - item_array_t items; - changed_items_t categories_to_update; - item_array_t possible_broken_links; - cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. - std::string inventory_filename = getInvCacheAddres(owner_id); - const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; - std::string gzip_filename(inventory_filename); - gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); - bool remove_inventory_file = false; - if(fp) - { - fclose(fp); - fp = NULL; - if(gunzip_file(gzip_filename, inventory_filename)) - { - // we only want to remove the inventory file if it was - // gzipped before we loaded, and we successfully - // gunziped it. - remove_inventory_file = true; - } - else - { - LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; - } - } - bool is_cache_obsolete = false; - if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) - { - // We were able to find a cache of files. So, use what we - // found to generate a set of categories we should add. We - // will go through each category loaded and if the version - // does not match, invalidate the version. - S32 count = categories.size(); - cat_set_t::iterator not_cached = temp_cats.end(); - std::set cached_ids; - for(S32 i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = categories[i]; - cat_set_t::iterator cit = temp_cats.find(cat); - if (cit == temp_cats.end()) - { - continue; // cache corruption?? not sure why this happens -SJB - } - LLViewerInventoryCategory* tcat = *cit; - - if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) - { - tcat->setVersion(NO_VERSION); - LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; - } - - // we can safely ignore anything loaded from file, but - // not sent down in the skeleton. Must have been removed from inventory. - if (cit == not_cached) - { - continue; - } - else if (cat->getVersion() != tcat->getVersion()) - { - // if the cached version does not match the server version, - // throw away the version we have so we can fetch the - // correct contents the next time the viewer opens the folder. - tcat->setVersion(NO_VERSION); - } - else - { - cached_ids.insert(tcat->getUUID()); + } + } + + S32 cached_category_count = 0; + S32 cached_item_count = 0; + if(!temp_cats.empty()) + { + update_map_t child_counts; + cat_array_t categories; + item_array_t items; + changed_items_t categories_to_update; + item_array_t possible_broken_links; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. + std::string inventory_filename = getInvCacheAddres(owner_id); + const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; + std::string gzip_filename(inventory_filename); + gzip_filename.append(".gz"); + LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); + bool remove_inventory_file = false; + if(fp) + { + fclose(fp); + fp = NULL; + if(gunzip_file(gzip_filename, inventory_filename)) + { + // we only want to remove the inventory file if it was + // gzipped before we loaded, and we successfully + // gunziped it. + remove_inventory_file = true; + } + else + { + LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; + } + } + bool is_cache_obsolete = false; + if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) + { + // We were able to find a cache of files. So, use what we + // found to generate a set of categories we should add. We + // will go through each category loaded and if the version + // does not match, invalidate the version. + S32 count = categories.size(); + cat_set_t::iterator not_cached = temp_cats.end(); + std::set cached_ids; + for(S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories[i]; + cat_set_t::iterator cit = temp_cats.find(cat); + if (cit == temp_cats.end()) + { + continue; // cache corruption?? not sure why this happens -SJB + } + LLViewerInventoryCategory* tcat = *cit; + + if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) + { + tcat->setVersion(NO_VERSION); + LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; + } + + // we can safely ignore anything loaded from file, but + // not sent down in the skeleton. Must have been removed from inventory. + if (cit == not_cached) + { + continue; + } + else if (cat->getVersion() != tcat->getVersion()) + { + // if the cached version does not match the server version, + // throw away the version we have so we can fetch the + // correct contents the next time the viewer opens the folder. + tcat->setVersion(NO_VERSION); + } + else + { + cached_ids.insert(tcat->getUUID()); // At the moment download does not provide a thumbnail // uuid, use the one from cache tcat->setThumbnailUUID(cat->getThumbnailUUID()); - } - } - - // go ahead and add the cats returned during the download - std::set::const_iterator not_cached_id = cached_ids.end(); - cached_category_count = cached_ids.size(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - if(cached_ids.find((*it)->getUUID()) == not_cached_id) - { - // this check is performed so that we do not - // mark new folders in the skeleton (and not in cache) - // as being cached. - LLViewerInventoryCategory *llvic = (*it); - llvic->setVersion(NO_VERSION); - } - addCategory(*it); - ++child_counts[(*it)->getParentUUID()]; - } - - // Add all the items loaded which are parented to a - // category with a correctly cached parent - S32 bad_link_count = 0; - S32 good_link_count = 0; - S32 recovered_link_count = 0; - cat_map_t::iterator unparented = mCategoryMap.end(); - for(item_array_t::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) - { - LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - - if(cit != unparented) - { - const LLViewerInventoryCategory* cat = cit->second.get(); - if(cat->getVersion() != NO_VERSION) - { - // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. - if (item->getIsBrokenLink()) - { - //bad_link_count++; - LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " - << item->getName() << " itemID: " << item->getUUID() - << " assetID: " << item->getAssetUUID() - << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; - possible_broken_links.push_back(item); - continue; - } - else if (item->getIsLinkType()) - { - good_link_count++; - } - addItem(item); - cached_item_count += 1; - ++child_counts[cat->getUUID()]; - } - } - } - if (possible_broken_links.size() > 0) - { - for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); - item_iter != possible_broken_links.end(); - ++item_iter) - { - LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - const LLViewerInventoryCategory* cat = cit->second.get(); - if (item->getIsBrokenLink()) - { - bad_link_count++; - invalid_categories.insert(cit->second); - //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; - } - else - { - // was marked as broken because of loading order, its actually fine to load - addItem(item); - cached_item_count += 1; - ++child_counts[cat->getUUID()]; - recovered_link_count++; - } - } - - LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << good_link_count << " link items were successfully added. " - << recovered_link_count << " links added in recovery. " - << "The corresponding categories were invalidated." << LL_ENDL; - } - - } - else - { - // go ahead and add everything after stripping the version - // information. - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - LLViewerInventoryCategory *llvic = (*it); - llvic->setVersion(NO_VERSION); - addCategory(*it); - } - } - - // Invalidate all categories that failed fetching descendents for whatever - // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) - { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); - cat->setVersion(NO_VERSION); - LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; - } - if (invalid_categories.size() > 0) - { - LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; - } - - // At this point, we need to set the known descendents for each - // category which successfully cached so that we do not - // needlessly fetch descendents for categories which we have. - update_map_t::const_iterator no_child_counts = child_counts.end(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) - { - LLViewerInventoryCategory* cat = (*it).get(); - if(cat->getVersion() != NO_VERSION) - { - update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); - if(the_count != no_child_counts) - { - const S32 num_descendents = (*the_count).second.mValue; - cat->setDescendentCount(num_descendents); - } - else - { - cat->setDescendentCount(0); - } - } - } - - if(remove_inventory_file) - { - // clean up the gunzipped file. - LLFile::remove(inventory_filename); - } - if(is_cache_obsolete) - { - // If out of date, remove the gzipped file too. - LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; - LLFile::remove(gzip_filename); - } - categories.clear(); // will unref and delete entries - } - - LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count - << " categories and " << cached_item_count << " items from cache." - << LL_ENDL; - - return rv; + } + } + + // go ahead and add the cats returned during the download + std::set::const_iterator not_cached_id = cached_ids.end(); + cached_category_count = cached_ids.size(); + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + if(cached_ids.find((*it)->getUUID()) == not_cached_id) + { + // this check is performed so that we do not + // mark new folders in the skeleton (and not in cache) + // as being cached. + LLViewerInventoryCategory *llvic = (*it); + llvic->setVersion(NO_VERSION); + } + addCategory(*it); + ++child_counts[(*it)->getParentUUID()]; + } + + // Add all the items loaded which are parented to a + // category with a correctly cached parent + S32 bad_link_count = 0; + S32 good_link_count = 0; + S32 recovered_link_count = 0; + cat_map_t::iterator unparented = mCategoryMap.end(); + for(item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + + if(cit != unparented) + { + const LLViewerInventoryCategory* cat = cit->second.get(); + if(cat->getVersion() != NO_VERSION) + { + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. + if (item->getIsBrokenLink()) + { + //bad_link_count++; + LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " + << item->getName() << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; + possible_broken_links.push_back(item); + continue; + } + else if (item->getIsLinkType()) + { + good_link_count++; + } + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + } + } + } + if (possible_broken_links.size() > 0) + { + for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); + item_iter != possible_broken_links.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const LLViewerInventoryCategory* cat = cit->second.get(); + if (item->getIsBrokenLink()) + { + bad_link_count++; + invalid_categories.insert(cit->second); + //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; + } + else + { + // was marked as broken because of loading order, its actually fine to load + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + recovered_link_count++; + } + } + + LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << LL_ENDL; + } + + } + else + { + // go ahead and add everything after stripping the version + // information. + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + LLViewerInventoryCategory *llvic = (*it); + llvic->setVersion(NO_VERSION); + addCategory(*it); + } + } + + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; + } + if (invalid_categories.size() > 0) + { + LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + } + + // At this point, we need to set the known descendents for each + // category which successfully cached so that we do not + // needlessly fetch descendents for categories which we have. + update_map_t::const_iterator no_child_counts = child_counts.end(); + for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + { + LLViewerInventoryCategory* cat = (*it).get(); + if(cat->getVersion() != NO_VERSION) + { + update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); + if(the_count != no_child_counts) + { + const S32 num_descendents = (*the_count).second.mValue; + cat->setDescendentCount(num_descendents); + } + else + { + cat->setDescendentCount(0); + } + } + } + + if(remove_inventory_file) + { + // clean up the gunzipped file. + LLFile::remove(inventory_filename); + } + if(is_cache_obsolete) + { + // If out of date, remove the gzipped file too. + LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; + LLFile::remove(gzip_filename); + } + categories.clear(); // will unref and delete entries + } + + LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count + << " categories and " << cached_item_count << " items from cache." + << LL_ENDL; + + return rv; } // This is a brute force method to rebuild the entire parent-child // relations. The overall operation has O(NlogN) performance, which -// should be sufficient for our needs. +// should be sufficient for our needs. void LLInventoryModel::buildParentChildMap() { - LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; - - // *NOTE: I am skipping the logic around folder version - // synchronization here because it seems if a folder is lost, we - // might actually want to invalidate it at that point - not - // attempt to cache. More time & thought is necessary. - - // First the categories. We'll copy all of the categories into a - // temporary container to iterate over (oh for real iterators.) - // While we're at it, we'll allocate the arrays in the trees. - cat_array_t cats; - cat_array_t* catsp; - item_array_t* itemsp; - - for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - LLViewerInventoryCategory* cat = cit->second; - cats.push_back(cat); - if (mParentChildCategoryTree.count(cat->getUUID()) == 0) - { - llassert_always(mCategoryLock[cat->getUUID()] == false); - catsp = new cat_array_t; - mParentChildCategoryTree[cat->getUUID()] = catsp; - } - if (mParentChildItemTree.count(cat->getUUID()) == 0) - { - llassert_always(mItemLock[cat->getUUID()] == false); - itemsp = new item_array_t; - mParentChildItemTree[cat->getUUID()] = itemsp; - } - } - - // Insert a special parent for the root - so that lookups on - // LLUUID::null as the parent work correctly. This is kind of a - // blatent wastes of space since we allocate a block of memory for - // the array, but whatever - it's not that much space. - if (mParentChildCategoryTree.count(LLUUID::null) == 0) - { - catsp = new cat_array_t; - mParentChildCategoryTree[LLUUID::null] = catsp; - } - - // Now we have a structure with all of the categories that we can - // iterate over and insert into the correct place in the child - // category tree. - S32 count = cats.size(); - S32 i; - S32 lost = 0; - cat_array_t lost_cats; - for(i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = cats.at(i); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp && - // Only the two root folders should be children of null. - // Others should go to lost & found. - (cat->getParentUUID().notNull() || - cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) - { - catsp->push_back(cat); - } - else - { - // *NOTE: This process could be a lot more efficient if we - // used the new MoveInventoryFolder message, but we would - // have to continue to do the update & build here. So, to - // implement it, we would need a set or map of uuid pairs - // which would be (folder_id, new_parent_id) to be sent up - // to the server. - LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " - << cat->getName() << LL_ENDL; - ++lost; - lost_cats.push_back(cat); - } - } - if(lost) - { - LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; - } - - // Do moves in a separate pass to make sure we've properly filed - // the FT_LOST_AND_FOUND category before we try to find its UUID. - for(i = 0; igetPreferredType(); - if(LLFolderType::FT_NONE == pref) - { - cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - } - else if(LLFolderType::FT_ROOT_INVENTORY == pref) - { - // it's the root - cat->setParent(LLUUID::null); - } - else - { - // it's a protected folder. - cat->setParent(gInventory.getRootFolderID()); - } - // FIXME note that updateServer() fails with protected - // types, so this will not work as intended in that case. - // UpdateServer uses AIS, AIS cat move is not implemented yet - // cat->updateServer(TRUE); - - // MoveInventoryFolder message, intentionally per item - cat->updateParentOnServer(FALSE); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp) - { - catsp->push_back(cat); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - - const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); - sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); - - - // Now the items. We allocated in the last step, so now all we - // have to do is iterate over the items and put them in the right - // place. - item_array_t items; - if(!mItemMap.empty()) - { - LLPointer item; - for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - item = (*iit).second; - items.push_back(item); - } - } - count = items.size(); - lost = 0; - uuid_vec_t lost_item_ids; - for(i = 0; i < count; ++i) - { - LLPointer item; - item = items.at(i); - itemsp = getUnlockedItemArray(item->getParentUUID()); - if(itemsp) - { - itemsp->push_back(item); - } - else - { - LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " - << item->getName() << LL_ENDL; - ++lost; - // plop it into the lost & found. - // - item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - // move it later using a special message to move items. If - // we update server here, the client might crash. - //item->updateServer(); - lost_item_ids.push_back(item->getUUID()); - itemsp = getUnlockedItemArray(item->getParentUUID()); - if(itemsp) - { - itemsp->push_back(item); - } - else - { - LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; - } - } - } - if(lost) - { - LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - for(uuid_vec_t::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it) - { - if(start_new_message) - { - start_new_message = FALSE; - msg->newMessageFast(_PREHASH_MoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOLFast(_PREHASH_Stamp, FALSE); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, (*it)); - msg->addUUIDFast(_PREHASH_FolderID, lnf); - msg->addString("NewName", NULL); - if(msg->isSendFull(NULL)) - { - start_new_message = TRUE; - gAgent.sendReliableMessage(); - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - } - } - - const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); - if (agent_inv_root_id.notNull()) - { - cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); - if(catsp) - { - // *HACK - fix root inventory folder - // some accounts has pbroken inventory root folders - - std::string name = "My Inventory"; - for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), - it_end = mParentChildCategoryTree.end(); it != it_end; ++it) - { - cat_array_t* cat_array = it->second; - for (cat_array_t::const_iterator cat_it = cat_array->begin(), - cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) - { - LLPointer category = *cat_it; - - if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) - continue; - if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) - { - if(category->getUUID()!=mRootFolderID) - { - LLUUID& new_inv_root_folder_id = const_cast(mRootFolderID); - new_inv_root_folder_id = category->getUUID(); - } - } - } - } - - LLPointer validation_info = validate(); - if (validation_info->mFatalErrorCount > 0) - { - // Fatal inventory error. Will not be able to engage in many inventory operations. - // This should be followed by an error dialog leading to logout. - LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " - << "Will not be able to do normal inventory operations in this session." - << LL_ENDL; - mIsAgentInvUsable = false; - } - else - { - mIsAgentInvUsable = true; - } - validation_info->mInitialized = true; - mValidationInfo = validation_info; - - // notifyObservers() has been moved to - // llstartup/idle_startup() after this func completes. - // Allows some system categories to be created before - // observers start firing. - } - } + LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; + + // *NOTE: I am skipping the logic around folder version + // synchronization here because it seems if a folder is lost, we + // might actually want to invalidate it at that point - not + // attempt to cache. More time & thought is necessary. + + // First the categories. We'll copy all of the categories into a + // temporary container to iterate over (oh for real iterators.) + // While we're at it, we'll allocate the arrays in the trees. + cat_array_t cats; + cat_array_t* catsp; + item_array_t* itemsp; + + for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + LLViewerInventoryCategory* cat = cit->second; + cats.push_back(cat); + if (mParentChildCategoryTree.count(cat->getUUID()) == 0) + { + llassert_always(mCategoryLock[cat->getUUID()] == false); + catsp = new cat_array_t; + mParentChildCategoryTree[cat->getUUID()] = catsp; + } + if (mParentChildItemTree.count(cat->getUUID()) == 0) + { + llassert_always(mItemLock[cat->getUUID()] == false); + itemsp = new item_array_t; + mParentChildItemTree[cat->getUUID()] = itemsp; + } + } + + // Insert a special parent for the root - so that lookups on + // LLUUID::null as the parent work correctly. This is kind of a + // blatent wastes of space since we allocate a block of memory for + // the array, but whatever - it's not that much space. + if (mParentChildCategoryTree.count(LLUUID::null) == 0) + { + catsp = new cat_array_t; + mParentChildCategoryTree[LLUUID::null] = catsp; + } + + // Now we have a structure with all of the categories that we can + // iterate over and insert into the correct place in the child + // category tree. + S32 count = cats.size(); + S32 i; + S32 lost = 0; + cat_array_t lost_cats; + for(i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = cats.at(i); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp && + // Only the two root folders should be children of null. + // Others should go to lost & found. + (cat->getParentUUID().notNull() || + cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY )) + { + catsp->push_back(cat); + } + else + { + // *NOTE: This process could be a lot more efficient if we + // used the new MoveInventoryFolder message, but we would + // have to continue to do the update & build here. So, to + // implement it, we would need a set or map of uuid pairs + // which would be (folder_id, new_parent_id) to be sent up + // to the server. + LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " + << cat->getName() << LL_ENDL; + ++lost; + lost_cats.push_back(cat); + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; + } + + // Do moves in a separate pass to make sure we've properly filed + // the FT_LOST_AND_FOUND category before we try to find its UUID. + for(i = 0; igetPreferredType(); + if(LLFolderType::FT_NONE == pref) + { + cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + } + else if(LLFolderType::FT_ROOT_INVENTORY == pref) + { + // it's the root + cat->setParent(LLUUID::null); + } + else + { + // it's a protected folder. + cat->setParent(gInventory.getRootFolderID()); + } + // FIXME note that updateServer() fails with protected + // types, so this will not work as intended in that case. + // UpdateServer uses AIS, AIS cat move is not implemented yet + // cat->updateServer(TRUE); + + // MoveInventoryFolder message, intentionally per item + cat->updateParentOnServer(FALSE); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if(catsp) + { + catsp->push_back(cat); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + + const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); + sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); + + + // Now the items. We allocated in the last step, so now all we + // have to do is iterate over the items and put them in the right + // place. + item_array_t items; + if(!mItemMap.empty()) + { + LLPointer item; + for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + item = (*iit).second; + items.push_back(item); + } + } + count = items.size(); + lost = 0; + uuid_vec_t lost_item_ids; + for(i = 0; i < count; ++i) + { + LLPointer item; + item = items.at(i); + itemsp = getUnlockedItemArray(item->getParentUUID()); + if(itemsp) + { + itemsp->push_back(item); + } + else + { + LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " + << item->getName() << LL_ENDL; + ++lost; + // plop it into the lost & found. + // + item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + // move it later using a special message to move items. If + // we update server here, the client might crash. + //item->updateServer(); + lost_item_ids.push_back(item->getUUID()); + itemsp = getUnlockedItemArray(item->getParentUUID()); + if(itemsp) + { + itemsp->push_back(item); + } + else + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; + } + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + for(uuid_vec_t::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it) + { + if(start_new_message) + { + start_new_message = FALSE; + msg->newMessageFast(_PREHASH_MoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addBOOLFast(_PREHASH_Stamp, FALSE); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, (*it)); + msg->addUUIDFast(_PREHASH_FolderID, lnf); + msg->addString("NewName", NULL); + if(msg->isSendFull(NULL)) + { + start_new_message = TRUE; + gAgent.sendReliableMessage(); + } + } + if(!start_new_message) + { + gAgent.sendReliableMessage(); + } + } + + const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); + if (agent_inv_root_id.notNull()) + { + cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); + if(catsp) + { + // *HACK - fix root inventory folder + // some accounts has pbroken inventory root folders + + std::string name = "My Inventory"; + for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), + it_end = mParentChildCategoryTree.end(); it != it_end; ++it) + { + cat_array_t* cat_array = it->second; + for (cat_array_t::const_iterator cat_it = cat_array->begin(), + cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) + { + LLPointer category = *cat_it; + + if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) + continue; + if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) + { + if(category->getUUID()!=mRootFolderID) + { + LLUUID& new_inv_root_folder_id = const_cast(mRootFolderID); + new_inv_root_folder_id = category->getUUID(); + } + } + } + } + + LLPointer validation_info = validate(); + if (validation_info->mFatalErrorCount > 0) + { + // Fatal inventory error. Will not be able to engage in many inventory operations. + // This should be followed by an error dialog leading to logout. + LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " + << "Will not be able to do normal inventory operations in this session." + << LL_ENDL; + mIsAgentInvUsable = false; + } + else + { + mIsAgentInvUsable = true; + } + validation_info->mInitialized = true; + mValidationInfo = validation_info; + + // notifyObservers() has been moved to + // llstartup/idle_startup() after this func completes. + // Allows some system categories to be created before + // observers start firing. + } + } } // Would normally do this at construction but that's too early @@ -3202,22 +3202,22 @@ void LLInventoryModel::buildParentChildMap() // call set things up. void LLInventoryModel::initHttpRequest() { - if (! mHttpRequestFG) - { - // Haven't initialized, get to it - LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); - - mHttpRequestFG = new LLCore::HttpRequest; - mHttpRequestBG = new LLCore::HttpRequest; - mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); - mHttpOptions->setTransferTimeout(300); - mHttpOptions->setUseRetryAfter(true); - // mHttpOptions->setTrace(2); // Do tracing of requests + if (! mHttpRequestFG) + { + // Haven't initialized, get to it + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + + mHttpRequestFG = new LLCore::HttpRequest; + mHttpRequestBG = new LLCore::HttpRequest; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + mHttpOptions->setTransferTimeout(300); + mHttpOptions->setUseRetryAfter(true); + // mHttpOptions->setTrace(2); // Do tracing of requests mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); - mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); - mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); - mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); - } + mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); + mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); + } if (!gGenericDispatcher.isHandlerPresent("BulkUpdateInventory")) { @@ -3227,49 +3227,49 @@ void LLInventoryModel::initHttpRequest() void LLInventoryModel::handleResponses(bool foreground) { - if (foreground && mHttpRequestFG) - { - mHttpRequestFG->update(0); - } - else if (! foreground && mHttpRequestBG) - { - mHttpRequestBG->update(50000L); - } + if (foreground && mHttpRequestFG) + { + mHttpRequestFG->update(0); + } + else if (! foreground && mHttpRequestBG) + { + mHttpRequestBG->update(50000L); + } } LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground, - const std::string & url, - const LLSD & body, - const LLCore::HttpHandler::ptr_t &handler, - const char * const message) + const std::string & url, + const LLSD & body, + const LLCore::HttpHandler::ptr_t &handler, + const char * const message) { - if (! mHttpRequestFG) - { - // We do the initialization late and lazily as this class is - // statically-constructed and not all the bits are ready at - // that time. - initHttpRequest(); - } - - LLCore::HttpRequest * request(foreground ? mHttpRequestFG : mHttpRequestBG); - LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); - - handle = LLCoreHttpUtil::requestPostWithLLSD(request, - mHttpPolicyClass, - url, - body, - mHttpOptions, - mHttpHeaders, - handler); - if (LLCORE_HTTP_HANDLE_INVALID == handle) - { - LLCore::HttpStatus status(request->getStatus()); - LL_WARNS(LOG_INV) << "HTTP POST request failed for " << message - << ", Status: " << status.toTerseString() - << " Reason: '" << status.toString() << "'" - << LL_ENDL; - } - return handle; + if (! mHttpRequestFG) + { + // We do the initialization late and lazily as this class is + // statically-constructed and not all the bits are ready at + // that time. + initHttpRequest(); + } + + LLCore::HttpRequest * request(foreground ? mHttpRequestFG : mHttpRequestBG); + LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + + handle = LLCoreHttpUtil::requestPostWithLLSD(request, + mHttpPolicyClass, + url, + body, + mHttpOptions, + mHttpHeaders, + handler); + if (LLCORE_HTTP_HANDLE_INVALID == handle) + { + LLCore::HttpStatus status(request->getStatus()); + LL_WARNS(LOG_INV) << "HTTP POST request failed for " << message + << ", Status: " << status.toTerseString() + << " Reason: '" << status.toString() << "'" + << LL_ENDL; + } + return handle; } void LLInventoryModel::createCommonSystemCategories() @@ -3277,12 +3277,12 @@ void LLInventoryModel::createCommonSystemCategories() //amount of System Folder we should wait for sPendingSystemFolders = 9; - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS); gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MATERIAL); // probably should be server created gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX); @@ -3290,154 +3290,154 @@ void LLInventoryModel::createCommonSystemCategories() struct LLUUIDAndName { - LLUUIDAndName() {} - LLUUIDAndName(const LLUUID& id, const std::string& name); - bool operator==(const LLUUIDAndName& rhs) const; - bool operator<(const LLUUIDAndName& rhs) const; - bool operator>(const LLUUIDAndName& rhs) const; - - LLUUID mID; - std::string mName; + LLUUIDAndName() {} + LLUUIDAndName(const LLUUID& id, const std::string& name); + bool operator==(const LLUUIDAndName& rhs) const; + bool operator<(const LLUUIDAndName& rhs) const; + bool operator>(const LLUUIDAndName& rhs) const; + + LLUUID mID; + std::string mName; }; LLUUIDAndName::LLUUIDAndName(const LLUUID& id, const std::string& name) : - mID(id), mName(name) + mID(id), mName(name) { } bool LLUUIDAndName::operator==(const LLUUIDAndName& rhs) const { - return ((mID == rhs.mID) && (mName == rhs.mName)); + return ((mID == rhs.mID) && (mName == rhs.mName)); } bool LLUUIDAndName::operator<(const LLUUIDAndName& rhs) const { - return (mID < rhs.mID); + return (mID < rhs.mID); } bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const { - return (mID > rhs.mID); + return (mID > rhs.mID); } // static bool LLInventoryModel::loadFromFile(const std::string& filename, - LLInventoryModel::cat_array_t& categories, - LLInventoryModel::item_array_t& items, - LLInventoryModel::changed_items_t& cats_to_update, - bool &is_cache_obsolete) + LLInventoryModel::cat_array_t& categories, + LLInventoryModel::item_array_t& items, + LLInventoryModel::changed_items_t& cats_to_update, + bool &is_cache_obsolete) { LL_PROFILE_ZONE_NAMED("inventory load from file"); - if(filename.empty()) - { - LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; - return false; - } - LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; - - llifstream file(filename.c_str()); - - if (!file.is_open()) - { - LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; - return false; - } - - is_cache_obsolete = true; // Obsolete until proven current - - //U64 lines_count = 0U; - std::string line; - LLPointer parser = new LLSDNotationParser(); - while (std::getline(file, line)) - { - LLSD s_item; - std::istringstream iss(line); - if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; - break; - } - - if (s_item.has("inv_cache_version")) - { - S32 version = s_item["inv_cache_version"].asInteger(); - if (version == sCurrentInvCacheVersion) - { - // Cache is up to date - is_cache_obsolete = false; - continue; - } - else - { - LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; - break; - } - } - else if (s_item.has("cat_id")) - { - if (is_cache_obsolete) - break; - - LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importLLSD(s_item)) - { - categories.push_back(inv_cat); - } - } - else if (s_item.has("item_id")) - { - if (is_cache_obsolete) - break; - - LLPointer inv_item = new LLViewerInventoryItem; - if( inv_item->fromLLSD(s_item) ) - { - if(inv_item->getUUID().isNull()) - { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - } - else - { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) - { - cats_to_update.insert(inv_item->getParentUUID()); - } - else - { - items.push_back(inv_item); - } - } - } - } + if(filename.empty()) + { + LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL; + return false; + } + LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; + + llifstream file(filename.c_str()); + + if (!file.is_open()) + { + LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; + return false; + } + + is_cache_obsolete = true; // Obsolete until proven current + + //U64 lines_count = 0U; + std::string line; + LLPointer parser = new LLSDNotationParser(); + while (std::getline(file, line)) + { + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; + break; + } + + if (s_item.has("inv_cache_version")) + { + S32 version = s_item["inv_cache_version"].asInteger(); + if (version == sCurrentInvCacheVersion) + { + // Cache is up to date + is_cache_obsolete = false; + continue; + } + else + { + LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; + break; + } + } + else if (s_item.has("cat_id")) + { + if (is_cache_obsolete) + break; + + LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if(inv_cat->importLLSD(s_item)) + { + categories.push_back(inv_cat); + } + } + else if (s_item.has("item_id")) + { + if (is_cache_obsolete) + break; + + LLPointer inv_item = new LLViewerInventoryItem; + if( inv_item->fromLLSD(s_item) ) + { + if(inv_item->getUUID().isNull()) + { + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; + } + else + { + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } + } + } + } // TODO(brad) - figure out how to reenable this without breaking everything else -// static constexpr U64 BATCH_SIZE = 512U; -// if ((++lines_count % BATCH_SIZE) == 0) -// { -// // SL-19968 - make sure message system code gets a chance to run every so often -// pump_idle_startup_network(); -// } - } +// static constexpr U64 BATCH_SIZE = 512U; +// if ((++lines_count % BATCH_SIZE) == 0) +// { +// // SL-19968 - make sure message system code gets a chance to run every so often +// pump_idle_startup_network(); +// } + } - file.close(); + file.close(); - return !is_cache_obsolete; + return !is_cache_obsolete; } // static bool LLInventoryModel::saveToFile(const std::string& filename, - const cat_array_t& categories, - const item_array_t& items) + const cat_array_t& categories, + const item_array_t& items) { - if (filename.empty()) - { - LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; - return false; - } + if (filename.empty()) + { + LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; + return false; + } - LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; + LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; try { @@ -3509,46 +3509,46 @@ bool LLInventoryModel::saveToFile(const std::string& filename, // static void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) { - //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate, - // processInventoryUpdate, - // NULL); - //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory, - // processUseCachedInventory, - // NULL); - msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem, - processUpdateCreateInventoryItem, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, - processRemoveInventoryItem, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, - processRemoveInventoryFolder, - NULL); - msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, - processRemoveInventoryObjects, - NULL); - msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory, - processSaveAssetIntoInventory, - NULL); - msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, - processBulkUpdateInventory, - NULL); - msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem); + //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate, + // processInventoryUpdate, + // NULL); + //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory, + // processUseCachedInventory, + // NULL); + msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem, + processUpdateCreateInventoryItem, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, + processRemoveInventoryItem, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, + processRemoveInventoryFolder, + NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, + processRemoveInventoryObjects, + NULL); + msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory, + processSaveAssetIntoInventory, + NULL); + msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, + processBulkUpdateInventory, + NULL); + msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem); } -// static +// static void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**) { - // do accounting and highlight new items if they arrive - if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) - { - U32 callback_id; - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); - msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id); + // do accounting and highlight new items if they arrive + if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) + { + U32 callback_id; + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); + msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id); - gInventoryCallbacks.fire(callback_id, item_id); + gInventoryCallbacks.fire(callback_id, item_id); // Message system at the moment doesn't support Thumbnails and potential // newer features so just rerequest whole item @@ -3556,251 +3556,251 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo // todo: instead of unpacking message fully, // grab only an item_id, then fetch LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true); - } + } } bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask) { - //make sure our added inventory observer is active - start_new_inventory_observer(); - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id - << LL_ENDL; - return false; - } - item_array_t items; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - // Does this loop ever execute more than once? - for(S32 i = 0; i < count; ++i) - { - LLPointer titem = new LLViewerInventoryItem; - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " - << titem->getUUID() << LL_ENDL; - items.push_back(titem); - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) - { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; - } - } - if(account) - { - gInventory.accountForUpdate(update); - } - - if (account) - { - mask |= LLInventoryObserver::CREATE; - } - //as above, this loop never seems to loop more than once per call - for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - gInventory.updateItem(*it, mask); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); - - return true; -} - -// static -void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) -{ - LLUUID item_id; - S32 count = msg->getNumberOfBlocksFast(msg_label); - LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; - uuid_vec_t item_ids; - update_map_t update; - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); - LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if(itemp) - { - LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; - // we only bother with the delete and account if we found - // the item - this is usually a back-up for permissions, - // so frequently the item will already be gone. - --update[itemp->getParentUUID()]; - item_ids.push_back(item_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; - gInventory.deleteObject(*it); - } -} - -// static -void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) -{ - LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; - LLUUID agent_id, item_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); - gInventory.notifyObservers(); -} + //make sure our added inventory observer is active + start_new_inventory_observer(); -// static -void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, - LLMessageSystem* msg) + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return false; + } + item_array_t items; + update_map_t update; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + // Does this loop ever execute more than once? + for(S32 i = 0; i < count; ++i) + { + LLPointer titem = new LLViewerInventoryItem; + titem->unpackMessage(msg, _PREHASH_InventoryData, i); + LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + // examine update for changes. + LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); + if(itemp) + { + if(titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + } + if(account) + { + gInventory.accountForUpdate(update); + } + + if (account) + { + mask |= LLInventoryObserver::CREATE; + } + //as above, this loop never seems to loop more than once per call + for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + gInventory.updateItem(*it, mask); + } + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); + + return true; +} + +// static +void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) +{ + LLUUID item_id; + S32 count = msg->getNumberOfBlocksFast(msg_label); + LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; + uuid_vec_t item_ids; + update_map_t update; + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); + LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if(itemp) + { + LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; + // we only bother with the delete and account if we found + // the item - this is usually a back-up for permissions, + // so frequently the item will already be gone. + --update[itemp->getParentUUID()]; + item_ids.push_back(item_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) + { + LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; + gInventory.deleteObject(*it); + } +} + +// static +void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) { - LLUUID folder_id; - uuid_vec_t folder_ids; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i); - LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id); - if(folderp) - { - --update[folderp->getParentUUID()]; - folder_ids.push_back(folder_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) - { - gInventory.deleteObject(*it); - } + LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; + LLUUID agent_id, item_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); + gInventory.notifyObservers(); } -// static +// static +void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, + LLMessageSystem* msg) +{ + LLUUID folder_id; + uuid_vec_t folder_ids; + update_map_t update; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i); + LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id); + if(folderp) + { + --update[folderp->getParentUUID()]; + folder_ids.push_back(folder_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) + { + gInventory.deleteObject(*it); + } +} + +// static void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, - void**) + void**) { - LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; - LLUUID agent_id, session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryFolder( agent_id, msg ); - gInventory.notifyObservers(); + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + gInventory.notifyObservers(); } -// static +// static void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, - void**) + void**) { - LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; - LLUUID agent_id, session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." - << LL_ENDL; - return; - } - LLInventoryModel::removeInventoryFolder( agent_id, msg ); - LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); - gInventory.notifyObservers(); + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." + << LL_ENDL; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); + gInventory.notifyObservers(); } -// static +// static void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, - void**) + void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." - << LL_ENDL; - return; - } - - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); - - // The viewer ignores the asset id because this message is only - // used for attachments/objects, so the asset id is not used in - // the viewer anyway. - LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" - << item_id << LL_ENDL; - LLViewerInventoryItem* item = gInventory.getItem( item_id ); - if( item ) - { - LLCategoryUpdate up(item->getParentUUID(), 0); - gInventory.accountForUpdate(up); - gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id); - gInventory.notifyObservers(); - } - else - { - LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" - " not found: " << item_id << LL_ENDL; - } - if(gViewerWindow) - { - gViewerWindow->getWindow()->decBusyCount(); - } + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." + << LL_ENDL; + return; + } + + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id); + + // The viewer ignores the asset id because this message is only + // used for attachments/objects, so the asset id is not used in + // the viewer anyway. + LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" + << item_id << LL_ENDL; + LLViewerInventoryItem* item = gInventory.getItem( item_id ); + if( item ) + { + LLCategoryUpdate up(item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id); + gInventory.notifyObservers(); + } + else + { + LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" + " not found: " << item_id << LL_ENDL; + } + if(gViewerWindow) + { + gViewerWindow->getWindow()->decBusyCount(); + } } // static void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; - return; - } - LLUUID tid; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; + return; + } + LLUUID tid; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); #ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; + LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; #endif - update_map_t update; - cat_array_t folders; - S32 count; - S32 i; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(i = 0; i < count; ++i) - { - LLPointer tfolder = new LLViewerInventoryCategory(gAgent.getID()); - tfolder->unpackMessage(msg, _PREHASH_FolderData, i); - LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" - << tfolder->getUUID() << ") in " << tfolder->getParentUUID() - << LL_ENDL; - + update_map_t update; + cat_array_t folders; + S32 count; + S32 i; + count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + for(i = 0; i < count; ++i) + { + LLPointer tfolder = new LLViewerInventoryCategory(gAgent.getID()); + tfolder->unpackMessage(msg, _PREHASH_FolderData, i); + LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" + << tfolder->getUUID() << ") in " << tfolder->getParentUUID() + << LL_ENDL; + // If the folder is a listing or a version folder, all we need to do is update the SLM data int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID()); if ((depth_folder == 1) || (depth_folder == 2)) @@ -3811,12 +3811,12 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLMarketplaceData::instance().getListing(listing_id); // In that case, there is no item to update so no callback -> we skip the rest of the update } - else if(tfolder->getUUID().notNull()) - { - folders.push_back(tfolder); - LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); - if(folderp) - { + else if(tfolder->getUUID().notNull()) + { + folders.push_back(tfolder); + LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { if (tfolder->getParentUUID() == folderp->getParentUUID()) @@ -3833,15 +3833,15 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - else - { - // we could not find the folder, so it is probably - // new. However, we only want to attempt accounting - // for the parent if we can find the parent. - folderp = gInventory.getCategory(tfolder->getParentUUID()); - if(folderp) - { + } + else + { + // we could not find the folder, so it is probably + // new. However, we only want to attempt accounting + // for the parent if we can find the parent. + folderp = gInventory.getCategory(tfolder->getParentUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { ++update[tfolder->getParentUUID()]; @@ -3850,51 +3850,51 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - } - } - } - - - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - uuid_vec_t wearable_ids; - item_array_t items; - std::list cblist; - for(i = 0; i < count; ++i) - { - LLPointer titem = new LLViewerInventoryItem; - titem->unpackMessage(msg, _PREHASH_ItemData, i); - LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " - << titem->getParentUUID() << LL_ENDL; - U32 callback_id; - msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); - if(titem->getUUID().notNull() ) // && callback_id.notNull() ) - { - items.push_back(titem); - cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); - if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) - { - wearable_ids.push_back(titem->getUUID()); - } - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) - { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); - if(folderp) - { + } + } + } + } + + + count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); + uuid_vec_t wearable_ids; + item_array_t items; + std::list cblist; + for(i = 0; i < count; ++i) + { + LLPointer titem = new LLViewerInventoryItem; + titem->unpackMessage(msg, _PREHASH_ItemData, i); + LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " + << titem->getParentUUID() << LL_ENDL; + U32 callback_id; + msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); + if(titem->getUUID().notNull() ) // && callback_id.notNull() ) + { + items.push_back(titem); + cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); + if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) + { + wearable_ids.push_back(titem->getUUID()); + } + // examine update for changes. + LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); + if(itemp) + { + if(titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); + if(folderp) + { if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { ++update[titem->getParentUUID()]; @@ -3903,18 +3903,18 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { folderp->fetch(); } - } - } - } - else - { - cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); - } - } - gInventory.accountForUpdate(update); - - for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) - { + } + } + } + else + { + cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); + } + } + gInventory.accountForUpdate(update); + + for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) + { gInventory.updateCategory(*cit); if ((*cit)->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { @@ -3924,100 +3924,100 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); } // else already called fetch() above - } - for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) - { - gInventory.updateItem(*iit); + } + for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) + { + gInventory.updateItem(*iit); // Temporary workaround: just fetch the item using AIS to get missing fields. // If this works fine we might want to extract 'ids only' from the message // then use AIS as a primary fetcher LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true); - } - gInventory.notifyObservers(); - - // The incoming inventory could span more than one BulkInventoryUpdate packet, - // so record the transaction ID for this purchase, then wear all clothing - // that comes in as part of that transaction ID. JC - if (LLInventoryState::sWearNewClothing) - { - LLInventoryState::sWearNewClothingTransactionID = tid; - LLInventoryState::sWearNewClothing = FALSE; - } - - if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) - { - count = wearable_ids.size(); - for (i = 0; i < count; ++i) - { - LLViewerInventoryItem* wearable_item; - wearable_item = gInventory.getItem(wearable_ids[i]); - LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); - } - } - - std::list::iterator inv_it; - for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) - { - InventoryCallbackInfo cbinfo = (*inv_it); - gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); - } + } + gInventory.notifyObservers(); + + // The incoming inventory could span more than one BulkInventoryUpdate packet, + // so record the transaction ID for this purchase, then wear all clothing + // that comes in as part of that transaction ID. JC + if (LLInventoryState::sWearNewClothing) + { + LLInventoryState::sWearNewClothingTransactionID = tid; + LLInventoryState::sWearNewClothing = FALSE; + } + + if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) + { + count = wearable_ids.size(); + for (i = 0; i < count; ++i) + { + LLViewerInventoryItem* wearable_item; + wearable_item = gInventory.getItem(wearable_ids[i]); + LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); + } + } + + std::list::iterator inv_it; + for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) + { + InventoryCallbackInfo cbinfo = (*inv_it); + gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); + } } // static void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) { - LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." - << LL_ENDL; - return; - } - - LLUUID item_id; - LLUUID folder_id; - std::string new_name; - bool anything_changed = false; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if(item) - { - LLPointer new_item = new LLViewerInventoryItem(item); - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); - msg->getString("InventoryData", "NewName", new_name, i); - - LL_DEBUGS() << "moving item " << item_id << " to folder " - << folder_id << LL_ENDL; - update_list_t update; - LLCategoryUpdate old_folder(item->getParentUUID(), -1); - update.push_back(old_folder); - LLCategoryUpdate new_folder(folder_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - new_item->setParent(folder_id); - if (new_name.length() > 0) - { - new_item->rename(new_name); - } - gInventory.updateItem(new_item); - anything_changed = true; - } - else - { - LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; - } - } - if(anything_changed) - { - gInventory.notifyObservers(); - } + LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." + << LL_ENDL; + return; + } + + LLUUID item_id; + LLUUID folder_id; + std::string new_name; + bool anything_changed = false; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if(item) + { + LLPointer new_item = new LLViewerInventoryItem(item); + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); + msg->getString("InventoryData", "NewName", new_name, i); + + LL_DEBUGS() << "moving item " << item_id << " to folder " + << folder_id << LL_ENDL; + update_list_t update; + LLCategoryUpdate old_folder(item->getParentUUID(), -1); + update.push_back(old_folder); + LLCategoryUpdate new_folder(folder_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + new_item->setParent(folder_id); + if (new_name.length() > 0) + { + new_item->rename(new_name); + } + gInventory.updateItem(new_item); + anything_changed = true; + } + else + { + LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; + } + } + if(anything_changed) + { + gInventory.notifyObservers(); + } } //---------------------------------------------------------------------------- @@ -4026,274 +4026,274 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purge_descendents_of(folder_id, NULL); + } + return false; } void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderType::EType preferred_type) { - if (!notification.empty()) - { - LLSD args; - if(LLFolderType::FT_TRASH == preferred_type) - { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - const LLUUID trash_id = findCategoryUUIDForType(preferred_type); - gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants - S32 item_count = items.size() + cats.size(); - args["COUNT"] = item_count; - } - LLNotificationsUtil::add(notification, args, LLSD(), - boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); - } - else - { - const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); - } + if (!notification.empty()) + { + LLSD args; + if(LLFolderType::FT_TRASH == preferred_type) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + const LLUUID trash_id = findCategoryUUIDForType(preferred_type); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants + S32 item_count = items.size() + cats.size(); + args["COUNT"] = item_count; + } + LLNotificationsUtil::add(notification, args, LLSD(), + boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); + } + else + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purge_descendents_of(folder_id, NULL); + } } //---------------------------------------------------------------------------- void LLInventoryModel::removeItem(const LLUUID& item_id) { - LLViewerInventoryItem* item = getItem(item_id); - if (! item) - { - LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; - } - else - { - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (new_parent.notNull()) - { - LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; - changeItemParent(item, new_parent, TRUE); - } - } + LLViewerInventoryItem* item = getItem(item_id); + if (! item) + { + LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (new_parent.notNull()) + { + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); + } + } } void LLInventoryModel::removeCategory(const LLUUID& category_id) { - if (! get_is_category_removable(this, category_id)) - { - return; - } - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - collectDescendents(category_id, descendent_categories, descendent_items, FALSE); - - for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); - iter != descendent_items.end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - const LLUUID& item_id = item->getUUID(); - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item_id)) - { - LLGestureMgr::instance().deactivateGesture(item_id); - } - } - - LLViewerInventoryCategory* cat = getCategory(category_id); - if (cat) - { - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (trash_id.notNull()) - { - changeCategoryParent(cat, trash_id, TRUE); - } - } - - checkTrashOverflow(); + if (! get_is_category_removable(this, category_id)) + { + return; + } + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + collectDescendents(category_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + const LLUUID& item_id = item->getUUID(); + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item_id)) + { + LLGestureMgr::instance().deactivateGesture(item_id); + } + } + + LLViewerInventoryCategory* cat = getCategory(category_id); + if (cat) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull()) + { + changeCategoryParent(cat, trash_id, TRUE); + } + } + + checkTrashOverflow(); } void LLInventoryModel::removeObject(const LLUUID& object_id) { - if(object_id.isNull()) - { - return; - } - - LLInventoryObject* obj = getObject(object_id); - if (dynamic_cast(obj)) - { - removeItem(object_id); - } - else if (dynamic_cast(obj)) - { - removeCategory(object_id); - } - else if (obj) - { - LL_WARNS("Inventory") << "object ID " << object_id - << " is an object of unrecognized class " - << typeid(*obj).name() << LL_ENDL; - } - else - { - LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; - } + if(object_id.isNull()) + { + return; + } + + LLInventoryObject* obj = getObject(object_id); + if (dynamic_cast(obj)) + { + removeItem(object_id); + } + else if (dynamic_cast(obj)) + { + removeCategory(object_id); + } + else if (obj) + { + LL_WARNS("Inventory") << "object ID " << object_id + << " is an object of unrecognized class " + << typeid(*obj).name() << LL_ENDL; + } + else + { + LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; + } } bool callback_preview_trash_folder(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - LLFloaterPreviewTrash::show(); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + LLFloaterPreviewTrash::show(); + } + return false; } void LLInventoryModel::checkTrashOverflow() { - static LLCachedControl trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); - - // Collect all descendants including those in subfolders. - // - // Note: Do we really need content of subfolders? - // This was made to prevent download of trash folder timeouting - // viewer and sub-folders are supposed to download independently. - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); - S32 item_count = items.size() + cats.size(); - - if (item_count >= trash_max_capacity) - { - if (LLFloaterPreviewTrash::isVisible()) - { - // bring to front - LLFloaterPreviewTrash::show(); - } - else - { - LLNotificationsUtil::add("TrashIsFull", LLSD(), LLSD(), - boost::bind(callback_preview_trash_folder, _1, _2)); - } - } + static LLCachedControl trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); + + // Collect all descendants including those in subfolders. + // + // Note: Do we really need content of subfolders? + // This was made to prevent download of trash folder timeouting + // viewer and sub-folders are supposed to download independently. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + S32 item_count = items.size() + cats.size(); + + if (item_count >= trash_max_capacity) + { + if (LLFloaterPreviewTrash::isVisible()) + { + // bring to front + LLFloaterPreviewTrash::show(); + } + else + { + LLNotificationsUtil::add("TrashIsFull", LLSD(), LLSD(), + boost::bind(callback_preview_trash_folder, _1, _2)); + } + } } const LLUUID &LLInventoryModel::getRootFolderID() const { - return mRootFolderID; + return mRootFolderID; } void LLInventoryModel::setRootFolderID(const LLUUID& val) { - mRootFolderID = val; + mRootFolderID = val; } const LLUUID &LLInventoryModel::getLibraryRootFolderID() const { - return mLibraryRootFolderID; + return mLibraryRootFolderID; } void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val) { - mLibraryRootFolderID = val; + mLibraryRootFolderID = val; } const LLUUID &LLInventoryModel::getLibraryOwnerID() const { - return mLibraryOwnerID; + return mLibraryOwnerID; } void LLInventoryModel::setLibraryOwnerID(const LLUUID& val) { - mLibraryOwnerID = val; + mLibraryOwnerID = val; } // static BOOL LLInventoryModel::getIsFirstTimeInViewer2() { - // Do not call this before parentchild map is built. - if (!gInventory.mIsAgentInvUsable) - { - LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; - return TRUE; - } - - return sFirstTimeInViewer2; + // Do not call this before parentchild map is built. + if (!gInventory.mIsAgentInvUsable) + { + LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; + return TRUE; + } + + return sFirstTimeInViewer2; } LLInventoryModel::item_array_t::iterator LLInventoryModel::findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) { - LLInventoryModel::item_array_t::iterator curr_item = items.begin(); - - while (curr_item != items.end()) - { - if ((*curr_item)->getUUID() == id) - { - break; - } - ++curr_item; - } - - return curr_item; + LLInventoryModel::item_array_t::iterator curr_item = items.begin(); + + while (curr_item != items.end()) + { + if ((*curr_item)->getUUID() == id) + { + break; + } + ++curr_item; + } + + return curr_item; } // static // * @param[in, out] items - vector with items to be updated. It should be sorted in a right way // * before calling this method. // * @param src_item_id - LLUUID of inventory item to be moved in new position -// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should +// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should // * be placed. -// * @param insert_before - bool indicating if src_item_id should be placed before or after +// * @param insert_before - bool indicating if src_item_id should be placed before or after // * dest_item_id. Default is true. void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id, bool insert_before) { - LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); - LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); - - // If one of the passed UUID is not in the item list, bail out - if ((it_src == items.end()) || (it_dest == items.end())) - return; - - // Erase the source element from the list, keep a copy before erasing. - LLViewerInventoryItem* src_item = *it_src; - items.erase(it_src); - - // Note: Target iterator is not valid anymore because the container was changed, so update it. - it_dest = findItemIterByUUID(items, dest_item_id); - - // Go to the next element if one wishes to insert after the dest element - if (!insert_before) - { - ++it_dest; - } - - // Reinsert the source item in the right place - if (it_dest != items.end()) - { - items.insert(it_dest, src_item); - } - else - { - // Append to the list if it_dest reached the end - items.push_back(src_item); - } + LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id); + LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id); + + // If one of the passed UUID is not in the item list, bail out + if ((it_src == items.end()) || (it_dest == items.end())) + return; + + // Erase the source element from the list, keep a copy before erasing. + LLViewerInventoryItem* src_item = *it_src; + items.erase(it_src); + + // Note: Target iterator is not valid anymore because the container was changed, so update it. + it_dest = findItemIterByUUID(items, dest_item_id); + + // Go to the next element if one wishes to insert after the dest element + if (!insert_before) + { + ++it_dest; + } + + // Reinsert the source item in the right place + if (it_dest != items.end()) + { + items.insert(it_dest, src_item); + } + else + { + // Append to the list if it_dest reached the end + items.push_back(src_item); + } } // See also LLInventorySort where landmarks in the Favorites folder are sorted. class LLViewerInventoryItemSort { public: - bool operator()(const LLPointer& a, const LLPointer& b) - { - return a->getSortField() < b->getSortField(); - } + bool operator()(const LLPointer& a, const LLPointer& b) + { + return a->getSortField() < b->getSortField(); + } }; //---------------------------------------------------------------------------- @@ -4301,95 +4301,95 @@ public: // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() const { - LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; - LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - const LLViewerInventoryCategory* cat = cit->second; - if(cat) - { - LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " - << cat->getVersion() << " " << cat->getDescendentCount() - << LL_ENDL; - } - else - { - LL_INFOS() << " NULL!" << LL_ENDL; - } - } - LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - const LLViewerInventoryItem* item = iit->second; - if(item) - { - LL_INFOS() << " " << item->getUUID() << " " - << item->getName() << LL_ENDL; - } - else - { - LL_INFOS() << " NULL!" << LL_ENDL; - } - } - LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; + LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; + LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLViewerInventoryCategory* cat = cit->second; + if(cat) + { + LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " + << cat->getVersion() << " " << cat->getDescendentCount() + << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLViewerInventoryItem* item = iit->second; + if(item) + { + LL_INFOS() << " " << item->getUUID() << " " + << item->getName() << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; } // Do various integrity checks on model, logging issues found and -// returning an overall good/bad flag. +// returning an overall good/bad flag. LLPointer LLInventoryModel::validate() const { - LLPointer validation_info = new LLInventoryValidationInfo; - S32 fatal_errs = 0; - S32 warning_count= 0; + LLPointer validation_info = new LLInventoryValidationInfo; + S32 fatal_errs = 0; + S32 warning_count= 0; S32 loop_count = 0; S32 orphaned_count = 0; - if (getRootFolderID().isNull()) - { - LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; - validation_info->mFatalNoRootFolder = true; + if (getRootFolderID().isNull()) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; + validation_info->mFatalNoRootFolder = true; fatal_errs++; - } - if (getLibraryRootFolderID().isNull()) - { - // Probably shouldn't be a fatality, inventory can function without a library - LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; - validation_info->mFatalNoLibraryRootFolder = true; + } + if (getLibraryRootFolderID().isNull()) + { + // Probably shouldn't be a fatality, inventory can function without a library + LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; + validation_info->mFatalNoLibraryRootFolder = true; fatal_errs++; - } - - if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) - { - // ParentChild should be one larger because of the special entry for null uuid. - LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() - << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; - - validation_info->mWarnings["category_map_size"]++; - warning_count++; - } - S32 cat_lock = 0; - S32 item_lock = 0; - S32 desc_unknown_count = 0; - S32 version_unknown_count = 0; - - typedef std::map ft_count_map; - ft_count_map ft_counts_under_root; - ft_count_map ft_counts_elsewhere; - - // Loop over all categories and check. - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) - { - const LLUUID& cat_id = cit->first; - const LLViewerInventoryCategory *cat = cit->second; - if (!cat) - { - LL_WARNS("Inventory") << "null cat" << LL_ENDL; - validation_info->mWarnings["null_cat"]++; - warning_count++; - continue; - } - LLUUID topmost_ancestor_id; - // Will leave as null uuid on failure + } + + if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) + { + // ParentChild should be one larger because of the special entry for null uuid. + LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + + validation_info->mWarnings["category_map_size"]++; + warning_count++; + } + S32 cat_lock = 0; + S32 item_lock = 0; + S32 desc_unknown_count = 0; + S32 version_unknown_count = 0; + + typedef std::map ft_count_map; + ft_count_map ft_counts_under_root; + ft_count_map ft_counts_elsewhere; + + // Loop over all categories and check. + for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + const LLUUID& cat_id = cit->first; + const LLViewerInventoryCategory *cat = cit->second; + if (!cat) + { + LL_WARNS("Inventory") << "null cat" << LL_ENDL; + validation_info->mWarnings["null_cat"]++; + warning_count++; + continue; + } + LLUUID topmost_ancestor_id; + // Will leave as null uuid on failure EAncestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id); switch (res) { @@ -4403,361 +4403,361 @@ LLPointer LLInventoryModel::validate() const break; default: LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL; - validation_info->mWarnings["unknown_ancestor_status"]++; + validation_info->mWarnings["unknown_ancestor_status"]++; warning_count++; break; } - if (cat_id != cat->getUUID()) - { - LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; - validation_info->mWarnings["cat_id_index_mismatch"]++; - warning_count++; - } - - if (cat->getParentUUID().isNull()) - { - if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" - << getRootFolderID() << ") or library root (" - << getLibraryRootFolderID() << ")" << LL_ENDL; - validation_info->mWarnings["null_parent"]++; - warning_count++; - } - } - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(cat_id,cats,items); - if (!cats || !items) - { - LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; - validation_info->mWarnings["direct_descendents"]++; - warning_count++; - continue; - } - if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) - { - desc_unknown_count++; - } - else if (cats->size() + items->size() != cat->getDescendentCount()) - { - // In the case of library this is not unexpected, since - // different user accounts may be getting the library - // contents from different inventory hosts. - if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() +items->size() << LL_ENDL; - validation_info->mWarnings["invalid_descendent_count"]++; - warning_count++; - } - } - if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) - { - version_unknown_count++; - } - auto cat_lock_it = mCategoryLock.find(cat_id); - if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) - { - cat_lock++; - } - auto item_lock_it = mItemLock.find(cat_id); - if (item_lock_it != mItemLock.end() && item_lock_it->second) - { - item_lock++; - } - for (S32 i = 0; isize(); i++) - { - LLViewerInventoryItem *item = items->at(i); - - if (!item) - { - LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; - validation_info->mWarnings["null_item_at_index"]++; - warning_count++; - continue; - } - - const LLUUID& item_id = item->getUUID(); - - if (item->getParentUUID() != cat_id) - { - LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " - << item->getParentUUID() << " expected " << cat_id - << LL_ENDL; - validation_info->mWarnings["wrong_parent_for_item"]++; - warning_count++; - } - - - // Entries in items and mItemMap should correspond. - item_map_t::const_iterator it = mItemMap.find(item_id); - if (it == mItemMap.end()) - { - LL_WARNS("Inventory") << "item " << item_id << " found as child of " - << cat_id << " but not in top level mItemMap" << LL_ENDL; - validation_info->mWarnings["item_not_in_top_map"]++; - warning_count++; - } - else - { - LLViewerInventoryItem *top_item = it->second; - if (top_item != item) - { - LL_WARNS("Inventory") << "item mismatch, item_id " << item_id - << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; - } - } - - // Topmost ancestor should be root or library. - LLUUID topmost_ancestor_id; + if (cat_id != cat->getUUID()) + { + LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + validation_info->mWarnings["cat_id_index_mismatch"]++; + warning_count++; + } + + if (cat->getParentUUID().isNull()) + { + if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + validation_info->mWarnings["null_parent"]++; + warning_count++; + } + } + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(cat_id,cats,items); + if (!cats || !items) + { + LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; + validation_info->mWarnings["direct_descendents"]++; + warning_count++; + continue; + } + if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + { + desc_unknown_count++; + } + else if (cats->size() + items->size() != cat->getDescendentCount()) + { + // In the case of library this is not unexpected, since + // different user accounts may be getting the library + // contents from different inventory hosts. + if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + validation_info->mWarnings["invalid_descendent_count"]++; + warning_count++; + } + } + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + version_unknown_count++; + } + auto cat_lock_it = mCategoryLock.find(cat_id); + if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) + { + cat_lock++; + } + auto item_lock_it = mItemLock.find(cat_id); + if (item_lock_it != mItemLock.end() && item_lock_it->second) + { + item_lock++; + } + for (S32 i = 0; isize(); i++) + { + LLViewerInventoryItem *item = items->at(i); + + if (!item) + { + LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + validation_info->mWarnings["null_item_at_index"]++; + warning_count++; + continue; + } + + const LLUUID& item_id = item->getUUID(); + + if (item->getParentUUID() != cat_id) + { + LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + validation_info->mWarnings["wrong_parent_for_item"]++; + warning_count++; + } + + + // Entries in items and mItemMap should correspond. + item_map_t::const_iterator it = mItemMap.find(item_id); + if (it == mItemMap.end()) + { + LL_WARNS("Inventory") << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + validation_info->mWarnings["item_not_in_top_map"]++; + warning_count++; + } + else + { + LLViewerInventoryItem *top_item = it->second; + if (top_item != item) + { + LL_WARNS("Inventory") << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + } + } + + // Topmost ancestor should be root or library. + LLUUID topmost_ancestor_id; EAncestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); - if (found != ANCESTOR_OK) - { - LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; - validation_info->mWarnings["topmost_ancestor_not_found"]++; - warning_count++; - } - else - { - if (topmost_ancestor_id != getRootFolderID() && - topmost_ancestor_id != getLibraryRootFolderID()) - { - LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id - << " got " << topmost_ancestor_id - << " expected " << getRootFolderID() - << " or " << getLibraryRootFolderID() << LL_ENDL; - validation_info->mWarnings["topmost_ancestor_not_recognized"]++; - warning_count++; - } - } - } - - // Does this category appear as a child of its supposed parent? - const LLUUID& parent_id = cat->getParentUUID(); - if (!parent_id.isNull()) - { - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(parent_id,cats,items); - if (!cats) - { - LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + if (found != ANCESTOR_OK) + { + LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; + validation_info->mWarnings["topmost_ancestor_not_found"]++; + warning_count++; + } + else + { + if (topmost_ancestor_id != getRootFolderID() && + topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + validation_info->mWarnings["topmost_ancestor_not_recognized"]++; + warning_count++; + } + } + } + + // Does this category appear as a child of its supposed parent? + const LLUUID& parent_id = cat->getParentUUID(); + if (!parent_id.isNull()) + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!cats) + { + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - else - { - bool found = false; - for (S32 i = 0; isize(); i++) - { - LLViewerInventoryCategory *kid_cat = cats->at(i); - if (kid_cat == cat) - { - found = true; - break; - } - } - if (!found) - { - LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i = 0; isize(); i++) + { + LLViewerInventoryCategory *kid_cat = cats->at(i); + if (kid_cat == cat) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - } - } - - // Update count of preferred types - LLFolderType::EType folder_type = cat->getPreferredType(); - bool cat_is_in_library = false; - LLUUID topmost_id; - if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID()) - { - cat_is_in_library = true; - } - if (!cat_is_in_library) - { - if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) - { - ft_counts_under_root[folder_type]++; - if (folder_type != LLFolderType::FT_NONE) - { - LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; - } - } - else - { - ft_counts_elsewhere[folder_type]++; - if (folder_type != LLFolderType::FT_NONE) - { - LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; - } - } - } - } - - // Loop over all items and check - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) - { - const LLUUID& item_id = iit->first; - LLViewerInventoryItem *item = iit->second; - if (item->getUUID() != item_id) - { - LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; - validation_info->mWarnings["item_id_mismatch"]++; - warning_count++; - } - - const LLUUID& parent_id = item->getParentUUID(); - if (parent_id.isNull()) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + } + } + } + + // Update count of preferred types + LLFolderType::EType folder_type = cat->getPreferredType(); + bool cat_is_in_library = false; + LLUUID topmost_id; + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANCESTOR_OK && topmost_id == getLibraryRootFolderID()) + { + cat_is_in_library = true; + } + if (!cat_is_in_library) + { + if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) + { + ft_counts_under_root[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + else + { + ft_counts_elsewhere[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + } + } + + // Loop over all items and check + for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + { + const LLUUID& item_id = iit->first; + LLViewerInventoryItem *item = iit->second; + if (item->getUUID() != item_id) + { + LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + validation_info->mWarnings["item_id_mismatch"]++; + warning_count++; + } + + const LLUUID& parent_id = item->getParentUUID(); + if (parent_id.isNull()) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; orphaned_count++; - } - else - { - cat_array_t* cats; - item_array_t* items; - getDirectDescendentsOf(parent_id,cats,items); - if (!items) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() - << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + } + else + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!items) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; orphaned_count++; - } - else - { - bool found = false; - for (S32 i=0; isize(); ++i) - { - if (items->at(i) == item) - { - found = true; - break; - } - } - if (!found) - { - LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() - << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (S32 i=0; isize(); ++i) + { + if (items->at(i) == item) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; orphaned_count++; - } - } - - } - // Link checking - if (item->getIsLinkType()) - { - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - LLViewerInventoryItem *target_item = getItem(target_id); - LLViewerInventoryCategory *target_cat = getCategory(target_id); - // Linked-to UUID should have back reference to this link. - if (!hasBacklinkInfo(link_id, target_id)) - { - LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() - << " missing backlink info at target_id " << target_id - << LL_ENDL; + } + } + + } + // Link checking + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; orphaned_count++; - } - // Links should have referents. - if (item->getActualType() == LLAssetType::AT_LINK && !target_item) - { - LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; orphaned_count++; - } - else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) - { - LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; orphaned_count++; - } - if (target_item && target_item->getIsLinkType()) - { - LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " - << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; - } - - // Links should not have backlinks. - std::pair range = mBacklinkMMap.equal_range(link_id); - if (range.first != range.second) - { - LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; - } - } - else - { - // Check the backlinks of a non-link item. - const LLUUID& target_id = item->getUUID(); - std::pair range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - const LLUUID& link_id = it->second; - LLViewerInventoryItem *link_item = getItem(link_id); - if (!link_item || !link_item->getIsLinkType()) - { - LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; - } - } - } - } - - // Check system folders - for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) - { - LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; - } - for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) - { - LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; - } - - static LLCachedControl fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); - static std::default_random_engine e{}; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } + } + else + { + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } + } + } + + // Check system folders + for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; + } + for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; + } + + static LLCachedControl fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); + static std::default_random_engine e{}; static std::uniform_int_distribution<> distrib(0, 1); - for (S32 ft=LLFolderType::FT_TEXTURE; ft(ft); - if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) - { - continue; - } - bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); - bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); - S32 count_under_root = ft_counts_under_root[folder_type]; - S32 count_elsewhere = ft_counts_elsewhere[folder_type]; - if (fake_system_folder_issues) - { - // Force all counts to be either 0 or 2, thus flagged as an error. - count_under_root = 2*distrib(e); - count_elsewhere = 2*distrib(e); - validation_info->mFatalQADebugMode = true; - } - if (is_singleton) - { - if (count_under_root==0) - { - LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; - // Need to create, if allowed. - if (is_automatic) - { - LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; - validation_info->mMissingRequiredSystemFolders.insert(folder_type); + for (S32 ft=LLFolderType::FT_TEXTURE; ft(ft); + if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) + { + continue; + } + bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); + bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); + S32 count_under_root = ft_counts_under_root[folder_type]; + S32 count_elsewhere = ft_counts_elsewhere[folder_type]; + if (fake_system_folder_issues) + { + // Force all counts to be either 0 or 2, thus flagged as an error. + count_under_root = 2*distrib(e); + count_elsewhere = 2*distrib(e); + validation_info->mFatalQADebugMode = true; + } + if (is_singleton) + { + if (count_under_root==0) + { + LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; + // Need to create, if allowed. + if (is_automatic) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; + validation_info->mMissingRequiredSystemFolders.insert(folder_type); fatal_errs++; - } - else - { - // Can create, and will when needed. - // (Not sure this is really a warning, but worth logging) - validation_info->mWarnings["missing_system_folder_can_create"]++; - warning_count++; - } - } - else if (count_under_root > 1) - { - validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); + } + else + { + // Can create, and will when needed. + // (Not sure this is really a warning, but worth logging) + validation_info->mWarnings["missing_system_folder_can_create"]++; + warning_count++; + } + } + else if (count_under_root > 1) + { + validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS // FT_MATERIAL might need to be automatic like the rest of upload folders @@ -4766,7 +4766,7 @@ LLPointer LLInventoryModel::validate() const { // It is a fatal problem or can lead to fatal problems for COF, // outfits, trash and other non-automatic folders. - validation_info->mFatalSystemDuplicate++; + validation_info->mFatalSystemDuplicate++; fatal_errs++; LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; } @@ -4775,74 +4775,74 @@ LLPointer LLInventoryModel::validate() const // For automatic folders it's not a fatal issue and shouldn't // break inventory or other functionality further // Exception: FT_SETTINGS is not automatic, but only deserves a warning. - validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++; + validation_info->mWarnings["non_fatal_system_duplicate_under_root"]++; warning_count++; LL_WARNS("Inventory") << "System folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; } - } - if (count_elsewhere > 0) - { - LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; - validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++; - warning_count++; - } - } - } - - - if (cat_lock > 0 || item_lock > 0) - { - LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " - << cat_lock << ", item arrays " << item_lock << LL_ENDL; - } - if (desc_unknown_count != 0) - { - LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; - } - if (version_unknown_count != 0) - { - LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; - } - - // FIXME need to fail login and tell user to retry, contact support if problem persists. - bool valid = (fatal_errs == 0); - LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL; - - validation_info->mFatalErrorCount = fatal_errs; - validation_info->mWarningCount = warning_count; + } + if (count_elsewhere > 0) + { + LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; + validation_info->mWarnings["non_fatal_system_duplicate_elsewhere"]++; + warning_count++; + } + } + } + + + if (cat_lock > 0 || item_lock > 0) + { + LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " + << cat_lock << ", item arrays " << item_lock << LL_ENDL; + } + if (desc_unknown_count != 0) + { + LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + } + if (version_unknown_count != 0) + { + LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + } + + // FIXME need to fail login and tell user to retry, contact support if problem persists. + bool valid = (fatal_errs == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warning_count << ", valid: " << valid << LL_ENDL; + + validation_info->mFatalErrorCount = fatal_errs; + validation_info->mWarningCount = warning_count; validation_info->mLoopCount = loop_count; validation_info->mOrphanedCount = orphaned_count; - return validation_info; + return validation_info; } // Provides a unix-style path from root, like "/My Inventory/Clothing/.../myshirt" std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const { - std::vector path_elts; - std::map visited; - while (obj != NULL && !visited[obj->getUUID()]) - { - path_elts.push_back(obj->getName()); - // avoid infinite loop in the unlikely event of a cycle - visited[obj->getUUID()] = true; - obj = getObject(obj->getParentUUID()); - } - std::stringstream s; - std::string delim("/"); - std::reverse(path_elts.begin(), path_elts.end()); - std::string result = "/" + boost::algorithm::join(path_elts, delim); - return result; + std::vector path_elts; + std::map visited; + while (obj != NULL && !visited[obj->getUUID()]) + { + path_elts.push_back(obj->getName()); + // avoid infinite loop in the unlikely event of a cycle + visited[obj->getUUID()] = true; + obj = getObject(obj->getParentUUID()); + } + std::stringstream s; + std::string delim("/"); + std::reverse(path_elts.begin(), path_elts.end()); + std::string result = "/" + boost::algorithm::join(path_elts, delim); + return result; } /* const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& path) { - vector path_elts; - boost::algorithm::split(path_elts, path, boost::is_any_of("/")); - for(path_elts, auto e) - { - } + vector path_elts; + boost::algorithm::split(path_elts, path, boost::is_any_of("/")); + for(path_elts, auto e) + { + } } */ @@ -4854,41 +4854,41 @@ const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& pat #if 0 BOOL decompress_file(const char* src_filename, const char* dst_filename) { - BOOL rv = FALSE; - gzFile src = NULL; - U8* buffer = NULL; - LLFILE* dst = NULL; - S32 bytes = 0; - const S32 DECOMPRESS_BUFFER_SIZE = 32000; - - // open the files - src = gzopen(src_filename, "rb"); - if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, "wb"); - if(!dst) goto err_decompress; - - // decompress. - buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; - - do - { - bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE); - if (bytes < 0) - { - goto err_decompress; - } - - fwrite(buffer, bytes, 1, dst); - } while(gzeof(src) == 0); - - // success - rv = TRUE; + BOOL rv = FALSE; + gzFile src = NULL; + U8* buffer = NULL; + LLFILE* dst = NULL; + S32 bytes = 0; + const S32 DECOMPRESS_BUFFER_SIZE = 32000; + + // open the files + src = gzopen(src_filename, "rb"); + if(!src) goto err_decompress; + dst = LLFile::fopen(dst_filename, "wb"); + if(!dst) goto err_decompress; + + // decompress. + buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; + + do + { + bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE); + if (bytes < 0) + { + goto err_decompress; + } + + fwrite(buffer, bytes, 1, dst); + } while(gzeof(src) == 0); + + // success + rv = TRUE; err_decompress: - if(src != NULL) gzclose(src); - if(buffer != NULL) delete[] buffer; - if(dst != NULL) fclose(dst); - return rv; + if(src != NULL) gzclose(src); + if(buffer != NULL) delete[] buffer; + if(dst != NULL) fclose(dst); + return rv; } #endif @@ -4898,163 +4898,163 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) ///---------------------------------------------------------------------------- LLInventoryModel::FetchItemHttpHandler::FetchItemHttpHandler(const LLSD & request_sd) - : LLCore::HttpHandler(), - mRequestSD(request_sd) + : LLCore::HttpHandler(), + mRequestSD(request_sd) {} LLInventoryModel::FetchItemHttpHandler::~FetchItemHttpHandler() {} void LLInventoryModel::FetchItemHttpHandler::onCompleted(LLCore::HttpHandle handle, - LLCore::HttpResponse * response) + LLCore::HttpResponse * response) { - do // Single-pass do-while used for common exit handling - { - LLCore::HttpStatus status(response->getStatus()); - // status = LLCore::HttpStatus(404); // Dev tool to force error handling - if (! status) - { - processFailure(status, response); - break; // Goto common exit - } - - LLCore::BufferArray * body(response->getBody()); - // body = NULL; // Dev tool to force error handling - if (! body || ! body->size()) - { - LL_WARNS(LOG_INV) << "Missing data in inventory item query." << LL_ENDL; - processFailure("HTTP response for inventory item query missing body", response); - break; // Goto common exit - } - - // body->write(0, "Garbage Response", 16); // Dev tool to force error handling - LLSD body_llsd; - if (! LLCoreHttpUtil::responseToLLSD(response, true, body_llsd)) - { - // INFOS-level logging will occur on the parsed failure - processFailure("HTTP response for inventory item query has malformed LLSD", response); - break; // Goto common exit - } - - // Expect top-level structure to be a map - // body_llsd = LLSD::emptyArray(); // Dev tool to force error handling - if (! body_llsd.isMap()) - { - processFailure("LLSD response for inventory item not a map", response); - break; // Goto common exit - } - - // Check for 200-with-error failures - // - // Original Responder-based serivce model didn't check for these errors. - // It may be more robust to ignore this condition. With aggregated requests, - // an error in one inventory item might take down the entire request. - // So if this instead broke up the aggregated items into single requests, - // maybe that would make progress. Or perhaps there's structured information - // that can tell us what went wrong. Need to dig into this and firm up - // the API. - // - // body_llsd["error"] = LLSD::emptyMap(); // Dev tool to force error handling - // body_llsd["error"]["identifier"] = "Development"; - // body_llsd["error"]["message"] = "You left development code in the viewer"; - if (body_llsd.has("error")) - { - processFailure("Inventory application error (200-with-error)", response); - break; // Goto common exit - } - - // Okay, process data if possible - processData(body_llsd, response); - } - while (false); + do // Single-pass do-while used for common exit handling + { + LLCore::HttpStatus status(response->getStatus()); + // status = LLCore::HttpStatus(404); // Dev tool to force error handling + if (! status) + { + processFailure(status, response); + break; // Goto common exit + } + + LLCore::BufferArray * body(response->getBody()); + // body = NULL; // Dev tool to force error handling + if (! body || ! body->size()) + { + LL_WARNS(LOG_INV) << "Missing data in inventory item query." << LL_ENDL; + processFailure("HTTP response for inventory item query missing body", response); + break; // Goto common exit + } + + // body->write(0, "Garbage Response", 16); // Dev tool to force error handling + LLSD body_llsd; + if (! LLCoreHttpUtil::responseToLLSD(response, true, body_llsd)) + { + // INFOS-level logging will occur on the parsed failure + processFailure("HTTP response for inventory item query has malformed LLSD", response); + break; // Goto common exit + } + + // Expect top-level structure to be a map + // body_llsd = LLSD::emptyArray(); // Dev tool to force error handling + if (! body_llsd.isMap()) + { + processFailure("LLSD response for inventory item not a map", response); + break; // Goto common exit + } + + // Check for 200-with-error failures + // + // Original Responder-based serivce model didn't check for these errors. + // It may be more robust to ignore this condition. With aggregated requests, + // an error in one inventory item might take down the entire request. + // So if this instead broke up the aggregated items into single requests, + // maybe that would make progress. Or perhaps there's structured information + // that can tell us what went wrong. Need to dig into this and firm up + // the API. + // + // body_llsd["error"] = LLSD::emptyMap(); // Dev tool to force error handling + // body_llsd["error"]["identifier"] = "Development"; + // body_llsd["error"]["message"] = "You left development code in the viewer"; + if (body_llsd.has("error")) + { + processFailure("Inventory application error (200-with-error)", response); + break; // Goto common exit + } + + // Okay, process data if possible + processData(body_llsd, response); + } + while (false); } void LLInventoryModel::FetchItemHttpHandler::processData(LLSD & content, LLCore::HttpResponse * response) { - start_new_inventory_observer(); + start_new_inventory_observer(); #if 0 - LLUUID agent_id; - agent_id = content["agent_id"].asUUID(); - if (agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id - << LL_ENDL; - return; - } + LLUUID agent_id; + agent_id = content["agent_id"].asUUID(); + if (agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return; + } #endif - - LLInventoryModel::item_array_t items; - LLInventoryModel::update_map_t update; - LLUUID folder_id; - LLSD content_items(content["items"]); - const S32 count(content_items.size()); - - // Does this loop ever execute more than once? - for (S32 i(0); i < count; ++i) - { - LLPointer titem = new LLViewerInventoryItem; - titem->unpackMessage(content_items[i]); - - LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " - << titem->getUUID() << LL_ENDL; - items.push_back(titem); - - // examine update for changes. - LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); - - if (itemp) - { - if (titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; - } - - if (folder_id.isNull()) - { - folder_id = titem->getParentUUID(); - } - } - - // as above, this loop never seems to loop more than once per call - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - gInventory.updateItem(*it); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); + + LLInventoryModel::item_array_t items; + LLInventoryModel::update_map_t update; + LLUUID folder_id; + LLSD content_items(content["items"]); + const S32 count(content_items.size()); + + // Does this loop ever execute more than once? + for (S32 i(0); i < count; ++i) + { + LLPointer titem = new LLViewerInventoryItem; + titem->unpackMessage(content_items[i]); + + LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + + // examine update for changes. + LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); + + if (itemp) + { + if (titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + + if (folder_id.isNull()) + { + folder_id = titem->getParentUUID(); + } + } + + // as above, this loop never seems to loop more than once per call + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + gInventory.updateItem(*it); + } + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); } void LLInventoryModel::FetchItemHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::HttpResponse * response) { - const std::string & ct(response->getContentType()); - LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" - << "[Status: " << status.toTerseString() << "]\n" - << "[Reason: " << status.toString() << "]\n" - << "[Content-type: " << ct << "]\n" - << "[Content (abridged): " - << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; - gInventory.notifyObservers(); + const std::string & ct(response->getContentType()); + LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" + << "[Status: " << status.toTerseString() << "]\n" + << "[Reason: " << status.toString() << "]\n" + << "[Content-type: " << ct << "]\n" + << "[Content (abridged): " + << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; + gInventory.notifyObservers(); } void LLInventoryModel::FetchItemHttpHandler::processFailure(const char * const reason, LLCore::HttpResponse * response) { - LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" - << "[Status: internal error]\n" - << "[Reason: " << reason << "]\n" - << "[Content (abridged): " - << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; - gInventory.notifyObservers(); + LL_WARNS(LOG_INV) << "Inventory item fetch failure\n" + << "[Status: internal error]\n" + << "[Reason: " << reason << "]\n" + << "[Content (abridged): " + << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL; + gInventory.notifyObservers(); } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 60edbfee88..a2a6210572 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lllocalbitmaps.cpp * @author Vaalith Jinn * @brief Local Bitmaps source @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, 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$ */ @@ -69,7 +69,7 @@ /*=======================================*/ /* Formal declarations, constants, etc. */ -/*=======================================*/ +/*=======================================*/ static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; static const BOOL LL_LOCAL_USE_MIPMAPS = true; @@ -80,57 +80,57 @@ static const S32 LL_LOCAL_UPDATE_RETRIES = 5; /*=======================================*/ /* LLLocalBitmap: unit class */ -/*=======================================*/ +/*=======================================*/ LLLocalBitmap::LLLocalBitmap(std::string filename) - : mFilename(filename) - , mShortName(gDirUtilp->getBaseFileName(filename, true)) - , mValid(false) - , mLastModified() - , mLinkStatus(LS_ON) - , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) + : mFilename(filename) + , mShortName(gDirUtilp->getBaseFileName(filename, true)) + , mValid(false) + , mLastModified() + , mLinkStatus(LS_ON) + , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) { - mTrackingID.generate(); - - /* extension */ - std::string temp_exten = gDirUtilp->getExtension(mFilename); - - if (temp_exten == "bmp") - { - mExtension = ET_IMG_BMP; - } - else if (temp_exten == "tga") - { - mExtension = ET_IMG_TGA; - } - else if (temp_exten == "jpg" || temp_exten == "jpeg") - { - mExtension = ET_IMG_JPG; - } - else if (temp_exten == "png") - { - mExtension = ET_IMG_PNG; - } - else - { - LL_WARNS() << "File of no valid extension given, local bitmap creation aborted." << "\n" - << "Filename: " << mFilename << LL_ENDL; - return; // no valid extension. - } - - /* next phase of unit creation is nearly the same as an update cycle. - we're running updateSelf as a special case with the optional UT_FIRSTUSE - which omits the parts associated with removing the outdated texture */ - mValid = updateSelf(UT_FIRSTUSE); + mTrackingID.generate(); + + /* extension */ + std::string temp_exten = gDirUtilp->getExtension(mFilename); + + if (temp_exten == "bmp") + { + mExtension = ET_IMG_BMP; + } + else if (temp_exten == "tga") + { + mExtension = ET_IMG_TGA; + } + else if (temp_exten == "jpg" || temp_exten == "jpeg") + { + mExtension = ET_IMG_JPG; + } + else if (temp_exten == "png") + { + mExtension = ET_IMG_PNG; + } + else + { + LL_WARNS() << "File of no valid extension given, local bitmap creation aborted." << "\n" + << "Filename: " << mFilename << LL_ENDL; + return; // no valid extension. + } + + /* next phase of unit creation is nearly the same as an update cycle. + we're running updateSelf as a special case with the optional UT_FIRSTUSE + which omits the parts associated with removing the outdated texture */ + mValid = updateSelf(UT_FIRSTUSE); } LLLocalBitmap::~LLLocalBitmap() { - // replace IDs with defaults, if set to do so. - if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 - { - replaceIDs(mWorldID, IMG_DEFAULT); - LLLocalBitmapMgr::getInstance()->doRebake(); - } + // replace IDs with defaults, if set to do so. + if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 + { + replaceIDs(mWorldID, IMG_DEFAULT); + LLLocalBitmapMgr::getInstance()->doRebake(); + } for (LLPointer &mat : mGLTFMaterialWithLocalTextures) { @@ -140,146 +140,146 @@ LLLocalBitmap::~LLLocalBitmap() mChangedSignal(getTrackingID(), getWorldID(), LLUUID()); mChangedSignal.disconnect_all_slots(); - // delete self from gimagelist - LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD); - gTextureList.deleteImage(image); + // delete self from gimagelist + LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD); + gTextureList.deleteImage(image); - if (image) - { - image->unref(); - } + if (image) + { + image->unref(); + } } /* accessors */ std::string LLLocalBitmap::getFilename() const { - return mFilename; + return mFilename; } std::string LLLocalBitmap::getShortName() const { - return mShortName; + return mShortName; } LLUUID LLLocalBitmap::getTrackingID() const { - return mTrackingID; + return mTrackingID; } LLUUID LLLocalBitmap::getWorldID() const { - return mWorldID; + return mWorldID; } bool LLLocalBitmap::getValid() const { - return mValid; + return mValid; } /* update functions */ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) { - bool updated = false; - - if (mLinkStatus == LS_ON) - { - // verifying that the file exists - if (gDirUtilp->fileExists(mFilename)) - { - // verifying that the file has indeed been modified + bool updated = false; + + if (mLinkStatus == LS_ON) + { + // verifying that the file exists + if (gDirUtilp->fileExists(mFilename)) + { + // verifying that the file has indeed been modified #ifndef LL_WINDOWS - const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); #else - const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); #endif - LLSD new_last_modified = asctime(localtime(&temp_time)); - - if (mLastModified.asString() != new_last_modified.asString()) - { - /* loading the image file and decoding it, here is a critical point which, - if fails, invalidates the whole update (or unit creation) process. */ - LLPointer raw_image = new LLImageRaw(); - if (decodeBitmap(raw_image)) - { - // decode is successful, we can safely proceed. - LLUUID old_id = LLUUID::null; - if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) - { - old_id = mWorldID; - } - mWorldID.generate(); - mLastModified = new_last_modified; - - LLPointer texture = new LLViewerFetchedTexture - ("file://"+mFilename, FTT_LOCAL_FILE, mWorldID, LL_LOCAL_USE_MIPMAPS); - - texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image); - texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); - texture->ref(); - - gTextureList.addImage(texture, TEX_LIST_STANDARD); - - if (optional_firstupdate != UT_FIRSTUSE) - { - // seek out everything old_id uses and replace it with mWorldID - replaceIDs(old_id, mWorldID); - - // remove old_id from gimagelist - LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_STANDARD); - if (image != NULL) - { - gTextureList.deleteImage(image); - image->unref(); - } - } - - mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; - updated = true; - } - - // if decoding failed, we get here and it will attempt to decode it in the next cycles - // until mUpdateRetries runs out. this is done because some software lock the bitmap while writing to it - else - { - if (mUpdateRetries) - { - mUpdateRetries--; - } - else - { - LL_WARNS() << "During the update process the following file was found" << "\n" - << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" - << "Filename: " << mFilename << "\n" - << "Disabling further update attempts for this file." << LL_ENDL; - - LLSD notif_args; - notif_args["FNAME"] = mFilename; - notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; - LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); - - mLinkStatus = LS_BROKEN; - } - } - } - - } // end if file exists - - else - { - LL_WARNS() << "During the update process, the following file was not found." << "\n" - << "Filename: " << mFilename << "\n" - << "Disabling further update attempts for this file." << LL_ENDL; - - LLSD notif_args; - notif_args["FNAME"] = mFilename; - LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); - - mLinkStatus = LS_BROKEN; - } - } - - return updated; + LLSD new_last_modified = asctime(localtime(&temp_time)); + + if (mLastModified.asString() != new_last_modified.asString()) + { + /* loading the image file and decoding it, here is a critical point which, + if fails, invalidates the whole update (or unit creation) process. */ + LLPointer raw_image = new LLImageRaw(); + if (decodeBitmap(raw_image)) + { + // decode is successful, we can safely proceed. + LLUUID old_id = LLUUID::null; + if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) + { + old_id = mWorldID; + } + mWorldID.generate(); + mLastModified = new_last_modified; + + LLPointer texture = new LLViewerFetchedTexture + ("file://"+mFilename, FTT_LOCAL_FILE, mWorldID, LL_LOCAL_USE_MIPMAPS); + + texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image); + texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); + texture->ref(); + + gTextureList.addImage(texture, TEX_LIST_STANDARD); + + if (optional_firstupdate != UT_FIRSTUSE) + { + // seek out everything old_id uses and replace it with mWorldID + replaceIDs(old_id, mWorldID); + + // remove old_id from gimagelist + LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_STANDARD); + if (image != NULL) + { + gTextureList.deleteImage(image); + image->unref(); + } + } + + mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; + updated = true; + } + + // if decoding failed, we get here and it will attempt to decode it in the next cycles + // until mUpdateRetries runs out. this is done because some software lock the bitmap while writing to it + else + { + if (mUpdateRetries) + { + mUpdateRetries--; + } + else + { + LL_WARNS() << "During the update process the following file was found" << "\n" + << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; + LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + } + + } // end if file exists + + else + { + LL_WARNS() << "During the update process, the following file was not found." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + + return updated; } boost::signals2::connection LLLocalBitmap::setChangedCallback(const LLLocalTextureCallback& cb) @@ -319,114 +319,114 @@ void LLLocalBitmap::addGLTFMaterial(LLGLTFMaterial* mat) bool LLLocalBitmap::decodeBitmap(LLPointer rawimg) { - bool decode_successful = false; - - switch (mExtension) - { - case ET_IMG_BMP: - { - LLPointer bmp_image = new LLImageBMP; - if (bmp_image->load(mFilename) && bmp_image->decode(rawimg, 0.0f)) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - case ET_IMG_TGA: - { - LLPointer tga_image = new LLImageTGA; - if ((tga_image->load(mFilename) && tga_image->decode(rawimg)) - && ((tga_image->getComponents() == 3) || (tga_image->getComponents() == 4))) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - case ET_IMG_JPG: - { - LLPointer jpeg_image = new LLImageJPEG; - if (jpeg_image->load(mFilename) && jpeg_image->decode(rawimg, 0.0f)) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - case ET_IMG_PNG: - { - LLPointer png_image = new LLImagePNG; - if (png_image->load(mFilename) && png_image->decode(rawimg, 0.0f)) - { - rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - decode_successful = true; - } - break; - } - - default: - { - // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens - // accessing mFilename and any other object properties might very well crash the viewer. - // getting here should be impossible, or there's been a pretty serious bug. - - LL_WARNS() << "During a decode attempt, the following local bitmap had no properly assigned extension." << LL_ENDL; - LL_WARNS() << "Filename: " << mFilename << LL_ENDL; - LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL; - mLinkStatus = LS_BROKEN; - } - } - - return decode_successful; + bool decode_successful = false; + + switch (mExtension) + { + case ET_IMG_BMP: + { + LLPointer bmp_image = new LLImageBMP; + if (bmp_image->load(mFilename) && bmp_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_TGA: + { + LLPointer tga_image = new LLImageTGA; + if ((tga_image->load(mFilename) && tga_image->decode(rawimg)) + && ((tga_image->getComponents() == 3) || (tga_image->getComponents() == 4))) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_JPG: + { + LLPointer jpeg_image = new LLImageJPEG; + if (jpeg_image->load(mFilename) && jpeg_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_PNG: + { + LLPointer png_image = new LLImagePNG; + if (png_image->load(mFilename) && png_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + default: + { + // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens + // accessing mFilename and any other object properties might very well crash the viewer. + // getting here should be impossible, or there's been a pretty serious bug. + + LL_WARNS() << "During a decode attempt, the following local bitmap had no properly assigned extension." << LL_ENDL; + LL_WARNS() << "Filename: " << mFilename << LL_ENDL; + LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL; + mLinkStatus = LS_BROKEN; + } + } + + return decode_successful; } void LLLocalBitmap::replaceIDs(const LLUUID& old_id, LLUUID new_id) { - // checking for misuse. - if (old_id == new_id) - { - LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" - << "Texture UUID: " << old_id.asString() << LL_ENDL; - return; - } + // checking for misuse. + if (old_id == new_id) + { + LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" + << "Texture UUID: " << old_id.asString() << LL_ENDL; + return; + } mChangedSignal(getTrackingID(), old_id, new_id); - // processing updates per channel; makes the process scalable. - // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. - updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); - updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); - updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); - - updateUserVolumes(old_id, new_id, LLRender::LIGHT_TEX); - updateUserVolumes(old_id, new_id, LLRender::SCULPT_TEX); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something? - - // default safeguard image for layers - if( new_id == IMG_DEFAULT ) - { - new_id = IMG_DEFAULT_AVATAR; - } - - /* It doesn't actually update all of those, it merely checks if any of them - contain the referenced ID and if so, updates. */ - updateUserLayers(old_id, new_id, LLWearableType::WT_ALPHA); - updateUserLayers(old_id, new_id, LLWearableType::WT_EYES); - updateUserLayers(old_id, new_id, LLWearableType::WT_GLOVES); - updateUserLayers(old_id, new_id, LLWearableType::WT_JACKET); - updateUserLayers(old_id, new_id, LLWearableType::WT_PANTS); - updateUserLayers(old_id, new_id, LLWearableType::WT_SHIRT); - updateUserLayers(old_id, new_id, LLWearableType::WT_SHOES); - updateUserLayers(old_id, new_id, LLWearableType::WT_SKIN); - updateUserLayers(old_id, new_id, LLWearableType::WT_SKIRT); - updateUserLayers(old_id, new_id, LLWearableType::WT_SOCKS); - updateUserLayers(old_id, new_id, LLWearableType::WT_TATTOO); - updateUserLayers(old_id, new_id, LLWearableType::WT_UNIVERSAL); - updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS); - updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT); + // processing updates per channel; makes the process scalable. + // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. + updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); + updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); + updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); + + updateUserVolumes(old_id, new_id, LLRender::LIGHT_TEX); + updateUserVolumes(old_id, new_id, LLRender::SCULPT_TEX); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something? + + // default safeguard image for layers + if( new_id == IMG_DEFAULT ) + { + new_id = IMG_DEFAULT_AVATAR; + } + + /* It doesn't actually update all of those, it merely checks if any of them + contain the referenced ID and if so, updates. */ + updateUserLayers(old_id, new_id, LLWearableType::WT_ALPHA); + updateUserLayers(old_id, new_id, LLWearableType::WT_EYES); + updateUserLayers(old_id, new_id, LLWearableType::WT_GLOVES); + updateUserLayers(old_id, new_id, LLWearableType::WT_JACKET); + updateUserLayers(old_id, new_id, LLWearableType::WT_PANTS); + updateUserLayers(old_id, new_id, LLWearableType::WT_SHIRT); + updateUserLayers(old_id, new_id, LLWearableType::WT_SHOES); + updateUserLayers(old_id, new_id, LLWearableType::WT_SKIN); + updateUserLayers(old_id, new_id, LLWearableType::WT_SKIRT); + updateUserLayers(old_id, new_id, LLWearableType::WT_SOCKS); + updateUserLayers(old_id, new_id, LLWearableType::WT_TATTOO); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNIVERSAL); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT); updateGLTFMaterials(old_id, new_id); } @@ -435,195 +435,195 @@ void LLLocalBitmap::replaceIDs(const LLUUID& old_id, LLUUID new_id) // in order to prevent multiple sendTEUpdate calls per object during updateUserPrims std::vector LLLocalBitmap::prepUpdateObjects(LLUUID old_id, U32 channel) { - std::vector obj_list; - LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); - - for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) - { - // getting an object from a face - LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; - - if(face_to_object) - { - LLViewerObject* affected_object = face_to_object->getViewerObject(); - - if(affected_object) - { - - // we have an object, we'll take it's UUID and compare it to - // whatever we already have in the returnable object list. - // if there is a match - we do not add (to prevent duplicates) - LLUUID mainlist_obj_id = affected_object->getID(); - bool add_object = true; - - // begin looking for duplicates - std::vector::iterator objlist_iter = obj_list.begin(); - for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) - { - LLViewerObject* obj = *objlist_iter; - if (obj->getID() == mainlist_obj_id) - { - add_object = false; // duplicate found. - } - } - // end looking for duplicates - - if(add_object) - { - obj_list.push_back(affected_object); - } - - } - - } - - } // end of face-iterating for() - - return obj_list; + std::vector obj_list; + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); + + for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) + { + // getting an object from a face + LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; + + if(face_to_object) + { + LLViewerObject* affected_object = face_to_object->getViewerObject(); + + if(affected_object) + { + + // we have an object, we'll take it's UUID and compare it to + // whatever we already have in the returnable object list. + // if there is a match - we do not add (to prevent duplicates) + LLUUID mainlist_obj_id = affected_object->getID(); + bool add_object = true; + + // begin looking for duplicates + std::vector::iterator objlist_iter = obj_list.begin(); + for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) + { + LLViewerObject* obj = *objlist_iter; + if (obj->getID() == mainlist_obj_id) + { + add_object = false; // duplicate found. + } + } + // end looking for duplicates + + if(add_object) + { + obj_list.push_back(affected_object); + } + + } + + } + + } // end of face-iterating for() + + return obj_list; } void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel) { - std::vector objectlist = prepUpdateObjects(old_id, channel); - - for(std::vector::iterator object_iterator = objectlist.begin(); - object_iterator != objectlist.end(); object_iterator++) - { - LLViewerObject* object = *object_iterator; - - if(object) - { - bool update_tex = false; - bool update_mat = false; - S32 num_faces = object->getNumFaces(); - - for (U8 face_iter = 0; face_iter < num_faces; face_iter++) - { - if (object->mDrawable) - { - LLFace* face = object->mDrawable->getFace(face_iter); - if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) - { - // these things differ per channel, unless there already is a universal - // texture setting function to setTE that takes channel as a param? - // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap - switch(channel) - { - case LLRender::DIFFUSE_MAP: - { + std::vector objectlist = prepUpdateObjects(old_id, channel); + + for(std::vector::iterator object_iterator = objectlist.begin(); + object_iterator != objectlist.end(); object_iterator++) + { + LLViewerObject* object = *object_iterator; + + if(object) + { + bool update_tex = false; + bool update_mat = false; + S32 num_faces = object->getNumFaces(); + + for (U8 face_iter = 0; face_iter < num_faces; face_iter++) + { + if (object->mDrawable) + { + LLFace* face = object->mDrawable->getFace(face_iter); + if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) + { + // these things differ per channel, unless there already is a universal + // texture setting function to setTE that takes channel as a param? + // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap + switch(channel) + { + case LLRender::DIFFUSE_MAP: + { object->setTETexture(face_iter, new_id); update_tex = true; - break; - } - - case LLRender::NORMAL_MAP: - { - object->setTENormalMap(face_iter, new_id); - update_mat = true; - update_tex = true; break; - } + } - case LLRender::SPECULAR_MAP: - { - object->setTESpecularMap(face_iter, new_id); + case LLRender::NORMAL_MAP: + { + object->setTENormalMap(face_iter, new_id); update_mat = true; - update_tex = true; + update_tex = true; break; - } - } - // end switch - - } - } - } - - if (update_tex) - { - object->sendTEUpdate(); - } - - if (update_mat) - { + } + + case LLRender::SPECULAR_MAP: + { + object->setTESpecularMap(face_iter, new_id); + update_mat = true; + update_tex = true; + break; + } + } + // end switch + + } + } + } + + if (update_tex) + { + object->sendTEUpdate(); + } + + if (update_mat) + { object->mDrawable->getVOVolume()->faceMappingChanged(); - } - } - } + } + } + } } void LLLocalBitmap::updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel) { - LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); - for (U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(channel); volume_iter++) - { - LLVOVolume* volobjp = (*old_texture->getVolumeList(channel))[volume_iter]; - switch (channel) - { - case LLRender::LIGHT_TEX: - { - if (volobjp->getLightTextureID() == old_id) - { - volobjp->setLightTextureID(new_id); - } - break; - } - case LLRender::SCULPT_TEX: - { - LLViewerObject* object = (LLViewerObject*)volobjp; - - if (object) - { - if (object->isSculpted() && object->getVolume() && - object->getVolume()->getParams().getSculptID() == old_id) - { - LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLSculptParams new_params(*old_params); - new_params.setSculptTexture(new_id, (*old_params).getSculptType()); - object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE); - } - } - } - } - } + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); + for (U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(channel); volume_iter++) + { + LLVOVolume* volobjp = (*old_texture->getVolumeList(channel))[volume_iter]; + switch (channel) + { + case LLRender::LIGHT_TEX: + { + if (volobjp->getLightTextureID() == old_id) + { + volobjp->setLightTextureID(new_id); + } + break; + } + case LLRender::SCULPT_TEX: + { + LLViewerObject* object = (LLViewerObject*)volobjp; + + if (object) + { + if (object->isSculpted() && object->getVolume() && + object->getVolume()->getParams().getSculptID() == old_id) + { + LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams new_params(*old_params); + new_params.setSculptTexture(new_id, (*old_params).getSculptType()); + object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE); + } + } + } + } + } } void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type) { - U32 count = gAgentWearables.getWearableCount(type); - for(U32 wearable_iter = 0; wearable_iter < count; wearable_iter++) - { - LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_iter); - if (wearable) - { - std::vector texture_list = wearable->getLocalTextureListSeq(); - for(std::vector::iterator texture_iter = texture_list.begin(); - texture_iter != texture_list.end(); texture_iter++) - { - LLLocalTextureObject* lto = *texture_iter; - - if (lto && lto->getID() == old_id) - { - U32 local_texlayer_index = 0; /* can't keep that as static const, gives errors, so i'm leaving this var here */ - LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind = - lto->getTexLayer(local_texlayer_index)->getTexLayerSet()->getBakedTexIndex(); - - LLAvatarAppearanceDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind); - if (reg_texind != LLAvatarAppearanceDefines::TEX_NUM_INDICES) - { - U32 index; - if (gAgentWearables.getWearableIndex(wearable,index)) - { - gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); - gAgentAvatarp->wearableUpdated(type); - /* telling the manager to rebake once update cycle is fully done */ - LLLocalBitmapMgr::getInstance()->setNeedsRebake(); - } - } - - } - } - } - } + U32 count = gAgentWearables.getWearableCount(type); + for(U32 wearable_iter = 0; wearable_iter < count; wearable_iter++) + { + LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_iter); + if (wearable) + { + std::vector texture_list = wearable->getLocalTextureListSeq(); + for(std::vector::iterator texture_iter = texture_list.begin(); + texture_iter != texture_list.end(); texture_iter++) + { + LLLocalTextureObject* lto = *texture_iter; + + if (lto && lto->getID() == old_id) + { + U32 local_texlayer_index = 0; /* can't keep that as static const, gives errors, so i'm leaving this var here */ + LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind = + lto->getTexLayer(local_texlayer_index)->getTexLayerSet()->getBakedTexIndex(); + + LLAvatarAppearanceDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind); + if (reg_texind != LLAvatarAppearanceDefines::TEX_NUM_INDICES) + { + U32 index; + if (gAgentWearables.getWearableIndex(wearable,index)) + { + gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); + gAgentAvatarp->wearableUpdated(type); + /* telling the manager to rebake once update cycle is fully done */ + LLLocalBitmapMgr::getInstance()->setNeedsRebake(); + } + } + + } + } + } + } } void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) @@ -688,304 +688,304 @@ void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) } LLAvatarAppearanceDefines::ETextureIndex LLLocalBitmap::getTexIndex( - LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind) + LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind) { - LLAvatarAppearanceDefines::ETextureIndex result = LLAvatarAppearanceDefines::TEX_NUM_INDICES; // using as a default/fail return. - - switch(type) - { - case LLWearableType::WT_ALPHA: - { - switch(baked_texind) - { - case LLAvatarAppearanceDefines::BAKED_EYES: - { - result = LLAvatarAppearanceDefines::TEX_EYES_ALPHA; - break; - } - - case LLAvatarAppearanceDefines::BAKED_HAIR: - { - result = LLAvatarAppearanceDefines::TEX_HAIR_ALPHA; - break; - } - - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_ALPHA; - break; - } - - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_ALPHA; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_ALPHA; - break; - } - - default: - { - break; - } - - } - break; - - } - - case LLWearableType::WT_EYES: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_EYES) - { - result = LLAvatarAppearanceDefines::TEX_EYES_IRIS; - } - - break; - } - - case LLWearableType::WT_GLOVES: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_GLOVES; - } - - break; - } - - case LLWearableType::WT_JACKET: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_JACKET; - } - else if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_JACKET; - } - - break; - } - - case LLWearableType::WT_PANTS: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_PANTS; - } - - break; - } - - case LLWearableType::WT_SHIRT: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_SHIRT; - } - - break; - } - - case LLWearableType::WT_SHOES: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_SHOES; - } - - break; - } - - case LLWearableType::WT_SKIN: - { - switch(baked_texind) - { - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_BODYPAINT; - break; - } - - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_BODYPAINT; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_BODYPAINT; - break; - } - - default: - { - break; - } - - } - break; - } - - case LLWearableType::WT_SKIRT: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_SKIRT) - { - result = LLAvatarAppearanceDefines::TEX_SKIRT; - } - - break; - } - - case LLWearableType::WT_SOCKS: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_SOCKS; - } - - break; - } - - case LLWearableType::WT_TATTOO: - { - switch (baked_texind) - { - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_TATTOO; - break; - } - - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_TATTOO; - break; - } - default: - { - break; - } - } - break; - - } - case LLWearableType::WT_UNIVERSAL: - { - switch (baked_texind) - { - - case LLAvatarAppearanceDefines::BAKED_SKIRT: - { - result = LLAvatarAppearanceDefines::TEX_SKIRT_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_EYES: - { - result = LLAvatarAppearanceDefines::TEX_EYES_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_HAIR: - { - result = LLAvatarAppearanceDefines::TEX_HAIR_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_LEFT_ARM: - { - result = LLAvatarAppearanceDefines::TEX_LEFT_ARM_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_LEFT_LEG: - { - result = LLAvatarAppearanceDefines::TEX_LEFT_LEG_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_AUX1: - { - result = LLAvatarAppearanceDefines::TEX_AUX1_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_AUX2: - { - result = LLAvatarAppearanceDefines::TEX_AUX2_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_AUX3: - { - result = LLAvatarAppearanceDefines::TEX_AUX3_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_UPPER: - { - result = LLAvatarAppearanceDefines::TEX_UPPER_UNIVERSAL_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_LOWER: - { - result = LLAvatarAppearanceDefines::TEX_LOWER_UNIVERSAL_TATTOO; - break; - } - case LLAvatarAppearanceDefines::BAKED_HEAD: - { - result = LLAvatarAppearanceDefines::TEX_HEAD_UNIVERSAL_TATTOO; - break; - } - - - default: - { - break; - } - - } - break; - } - - case LLWearableType::WT_UNDERPANTS: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) - { - result = LLAvatarAppearanceDefines::TEX_LOWER_UNDERPANTS; - } - - break; - } - - case LLWearableType::WT_UNDERSHIRT: - { - if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) - { - result = LLAvatarAppearanceDefines::TEX_UPPER_UNDERSHIRT; - } - - break; - } - - default: - { - LL_WARNS() << "Unknown wearable type: " << (int)type << "\n" - << "Baked Texture Index: " << (int)baked_texind << "\n" - << "Filename: " << mFilename << "\n" - << "TrackingID: " << mTrackingID << "\n" - << "InworldID: " << mWorldID << LL_ENDL; - } - - } - return result; + LLAvatarAppearanceDefines::ETextureIndex result = LLAvatarAppearanceDefines::TEX_NUM_INDICES; // using as a default/fail return. + + switch(type) + { + case LLWearableType::WT_ALPHA: + { + switch(baked_texind) + { + case LLAvatarAppearanceDefines::BAKED_EYES: + { + result = LLAvatarAppearanceDefines::TEX_EYES_ALPHA; + break; + } + + case LLAvatarAppearanceDefines::BAKED_HAIR: + { + result = LLAvatarAppearanceDefines::TEX_HAIR_ALPHA; + break; + } + + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_ALPHA; + break; + } + + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_ALPHA; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_ALPHA; + break; + } + + default: + { + break; + } + + } + break; + + } + + case LLWearableType::WT_EYES: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_EYES) + { + result = LLAvatarAppearanceDefines::TEX_EYES_IRIS; + } + + break; + } + + case LLWearableType::WT_GLOVES: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_GLOVES; + } + + break; + } + + case LLWearableType::WT_JACKET: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_JACKET; + } + else if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_JACKET; + } + + break; + } + + case LLWearableType::WT_PANTS: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_PANTS; + } + + break; + } + + case LLWearableType::WT_SHIRT: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_SHIRT; + } + + break; + } + + case LLWearableType::WT_SHOES: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_SHOES; + } + + break; + } + + case LLWearableType::WT_SKIN: + { + switch(baked_texind) + { + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_BODYPAINT; + break; + } + + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_BODYPAINT; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_BODYPAINT; + break; + } + + default: + { + break; + } + + } + break; + } + + case LLWearableType::WT_SKIRT: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_SKIRT) + { + result = LLAvatarAppearanceDefines::TEX_SKIRT; + } + + break; + } + + case LLWearableType::WT_SOCKS: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_SOCKS; + } + + break; + } + + case LLWearableType::WT_TATTOO: + { + switch (baked_texind) + { + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_TATTOO; + break; + } + + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_TATTOO; + break; + } + default: + { + break; + } + } + break; + + } + case LLWearableType::WT_UNIVERSAL: + { + switch (baked_texind) + { + + case LLAvatarAppearanceDefines::BAKED_SKIRT: + { + result = LLAvatarAppearanceDefines::TEX_SKIRT_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_EYES: + { + result = LLAvatarAppearanceDefines::TEX_EYES_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_HAIR: + { + result = LLAvatarAppearanceDefines::TEX_HAIR_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_LEFT_ARM: + { + result = LLAvatarAppearanceDefines::TEX_LEFT_ARM_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_LEFT_LEG: + { + result = LLAvatarAppearanceDefines::TEX_LEFT_LEG_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_AUX1: + { + result = LLAvatarAppearanceDefines::TEX_AUX1_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_AUX2: + { + result = LLAvatarAppearanceDefines::TEX_AUX2_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_AUX3: + { + result = LLAvatarAppearanceDefines::TEX_AUX3_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_UPPER: + { + result = LLAvatarAppearanceDefines::TEX_UPPER_UNIVERSAL_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_LOWER: + { + result = LLAvatarAppearanceDefines::TEX_LOWER_UNIVERSAL_TATTOO; + break; + } + case LLAvatarAppearanceDefines::BAKED_HEAD: + { + result = LLAvatarAppearanceDefines::TEX_HEAD_UNIVERSAL_TATTOO; + break; + } + + + default: + { + break; + } + + } + break; + } + + case LLWearableType::WT_UNDERPANTS: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_LOWER) + { + result = LLAvatarAppearanceDefines::TEX_LOWER_UNDERPANTS; + } + + break; + } + + case LLWearableType::WT_UNDERSHIRT: + { + if (baked_texind == LLAvatarAppearanceDefines::BAKED_UPPER) + { + result = LLAvatarAppearanceDefines::TEX_UPPER_UNDERSHIRT; + } + + break; + } + + default: + { + LL_WARNS() << "Unknown wearable type: " << (int)type << "\n" + << "Baked Texture Index: " << (int)baked_texind << "\n" + << "Filename: " << mFilename << "\n" + << "TrackingID: " << mTrackingID << "\n" + << "InworldID: " << mWorldID << LL_ENDL; + } + + } + return result; } /*=======================================*/ /* LLLocalBitmapTimer: timer class */ -/*=======================================*/ +/*=======================================*/ LLLocalBitmapTimer::LLLocalBitmapTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT) { } @@ -996,23 +996,23 @@ LLLocalBitmapTimer::~LLLocalBitmapTimer() void LLLocalBitmapTimer::startTimer() { - start(); + start(); } void LLLocalBitmapTimer::stopTimer() { - stop(); + stop(); } bool LLLocalBitmapTimer::tick() { - LLLocalBitmapMgr::getInstance()->doUpdates(); - return false; + LLLocalBitmapMgr::getInstance()->doUpdates(); + return false; } /*=======================================*/ /* LLLocalBitmapMgr: manager class */ -/*=======================================*/ +/*=======================================*/ LLLocalBitmapMgr::LLLocalBitmapMgr() { } @@ -1070,12 +1070,12 @@ LLUUID LLLocalBitmapMgr::addUnit(const std::string& filename) bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) { - std::string exten = gDirUtilp->getExtension(filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - std::string mImageLoadError; - LLImageDimensionsInfo image_info; - if (!image_info.load(filename,codec)) - { + std::string exten = gDirUtilp->getExtension(filename); + U32 codec = LLImageBase::getCodecFromExtension(exten); + std::string mImageLoadError; + LLImageDimensionsInfo image_info; + if (!image_info.load(filename,codec)) + { LLSD args; args["NAME"] = gDirUtilp->getBaseFileName(filename); if (!image_info.getWarningName().empty()) @@ -1083,69 +1083,69 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) args["REASON"] = LLTrans::getString(image_info.getWarningName()); } LLNotificationsUtil::add("CannotUploadTexture", args); - return false; - } + return false; + } - S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); - S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); + S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); - if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) - { - LLStringUtil::format_map_t args; - args["WIDTH"] = llformat("%d", max_width); - args["HEIGHT"] = llformat("%d", max_height); - mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); + if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) + { + LLStringUtil::format_map_t args; + args["WIDTH"] = llformat("%d", max_width); + args["HEIGHT"] = llformat("%d", max_height); + mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); - LLSD notif_args; - notif_args["REASON"] = mImageLoadError; + LLSD notif_args; + notif_args["REASON"] = mImageLoadError; notif_args["NAME"] = gDirUtilp->getBaseFileName(filename); - LLNotificationsUtil::add("CannotUploadTexture", notif_args); + LLNotificationsUtil::add("CannotUploadTexture", notif_args); - return false; - } + return false; + } - return true; + return true; } void LLLocalBitmapMgr::delUnit(LLUUID tracking_id) { - if (!mBitmapList.empty()) - { - std::vector to_delete; - for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { /* finding which ones we want deleted and making a separate list */ - LLLocalBitmap* unit = *iter; - if (unit->getTrackingID() == tracking_id) - { - to_delete.push_back(unit); - } - } - - for(std::vector::iterator del_iter = to_delete.begin(); - del_iter != to_delete.end(); del_iter++) - { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ - LLLocalBitmap* unit = *del_iter; - mBitmapList.remove(unit); - delete unit; - unit = NULL; - } - } + if (!mBitmapList.empty()) + { + std::vector to_delete; + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { /* finding which ones we want deleted and making a separate list */ + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + to_delete.push_back(unit); + } + } + + for(std::vector::iterator del_iter = to_delete.begin(); + del_iter != to_delete.end(); del_iter++) + { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ + LLLocalBitmap* unit = *del_iter; + mBitmapList.remove(unit); + delete unit; + unit = NULL; + } + } } LLUUID LLLocalBitmapMgr::getWorldID(const LLUUID &tracking_id) const { - LLUUID world_id = LLUUID::null; - - for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { - LLLocalBitmap* unit = *iter; - if (unit->getTrackingID() == tracking_id) - { - world_id = unit->getWorldID(); - } - } - - return world_id; + LLUUID world_id = LLUUID::null; + + for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + world_id = unit->getWorldID(); + } + } + + return world_id; } bool LLLocalBitmapMgr::isLocal(const LLUUID &world_id) const @@ -1163,18 +1163,18 @@ bool LLLocalBitmapMgr::isLocal(const LLUUID &world_id) const std::string LLLocalBitmapMgr::getFilename(const LLUUID &tracking_id) const { - std::string filename = ""; - - for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { - LLLocalBitmap* unit = *iter; - if (unit->getTrackingID() == tracking_id) - { - filename = unit->getFilename(); - } - } - - return filename; + std::string filename = ""; + + for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + filename = unit->getFilename(); + } + } + + return filename; } boost::signals2::connection LLLocalBitmapMgr::setOnChangedCallback(const LLUUID tracking_id, const LLLocalBitmap::LLLocalTextureCallback &cb) @@ -1205,18 +1205,18 @@ void LLLocalBitmapMgr::associateGLTFMaterial(const LLUUID tracking_id, LLGLTFMat void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) { - if (ctrl) - { + if (ctrl) + { std::string icon_name = LLInventoryIcon::getIconName( LLAssetType::AT_TEXTURE, LLInventoryType::IT_NONE); - if (!mBitmapList.empty()) - { - for (local_list_iter iter = mBitmapList.begin(); - iter != mBitmapList.end(); iter++) - { - LLSD element; + if (!mBitmapList.empty()) + { + for (local_list_iter iter = mBitmapList.begin(); + iter != mBitmapList.end(); iter++) + { + LLSD element; element["columns"][0]["column"] = "icon"; element["columns"][0]["type"] = "icon"; @@ -1231,39 +1231,39 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) data["type"] = (S32)LLAssetType::AT_TEXTURE; element["value"] = data; - ctrl->addElement(element); - } - } - } + ctrl->addElement(element); + } + } + } } void LLLocalBitmapMgr::doUpdates() { - // preventing theoretical overlap in cases with huge number of loaded images. - mTimer.stopTimer(); - mNeedsRebake = false; + // preventing theoretical overlap in cases with huge number of loaded images. + mTimer.stopTimer(); + mNeedsRebake = false; - for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) - { - (*iter)->updateSelf(); - } + for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) + { + (*iter)->updateSelf(); + } - doRebake(); - mTimer.startTimer(); + doRebake(); + mTimer.startTimer(); } void LLLocalBitmapMgr::setNeedsRebake() { - mNeedsRebake = true; + mNeedsRebake = true; } void LLLocalBitmapMgr::doRebake() { /* separated that from doUpdates to insure a rebake can be called separately during deletion */ - if (mNeedsRebake) - { - gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); - mNeedsRebake = false; - } + if (mNeedsRebake) + { + gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); + mNeedsRebake = false; + } } diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 96a39a3d66..84811ee14a 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -1,4 +1,4 @@ -/** +/** * @file lllocalbitmaps.h * @author Vaalith Jinn * @brief Local Bitmaps header @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, 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$ */ @@ -40,25 +40,25 @@ class LLGLTFMaterial; class LLLocalBitmap { - public: /* main */ - LLLocalBitmap(std::string filename); - ~LLLocalBitmap(); - - public: /* accessors */ - std::string getFilename() const; - std::string getShortName() const; - LLUUID getTrackingID() const; - LLUUID getWorldID() const; - bool getValid() const; - - public: /* self update public section */ - enum EUpdateType - { - UT_FIRSTUSE, - UT_REGUPDATE - }; - - bool updateSelf(EUpdateType = UT_REGUPDATE); + public: /* main */ + LLLocalBitmap(std::string filename); + ~LLLocalBitmap(); + + public: /* accessors */ + std::string getFilename() const; + std::string getShortName() const; + LLUUID getTrackingID() const; + LLUUID getWorldID() const; + bool getValid() const; + + public: /* self update public section */ + enum EUpdateType + { + UT_FIRSTUSE, + UT_REGUPDATE + }; + + bool updateSelf(EUpdateType = UT_REGUPDATE); typedef boost::signals2::signal raw); + private: /* self update private section */ + bool decodeBitmap(LLPointer raw); void replaceIDs(const LLUUID &old_id, LLUUID new_id); - std::vector prepUpdateObjects(LLUUID old_id, U32 channel); - void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); - void updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel); - void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type); + std::vector prepUpdateObjects(LLUUID old_id, U32 channel); + void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); + void updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel); + void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type); void updateGLTFMaterials(LLUUID old_id, LLUUID new_id); - LLAvatarAppearanceDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind); - - private: /* private enums */ - enum ELinkStatus - { - LS_ON, - LS_BROKEN, - }; - - enum EExtension - { - ET_IMG_BMP, - ET_IMG_TGA, - ET_IMG_JPG, - ET_IMG_PNG - }; - - private: /* members */ - std::string mFilename; - std::string mShortName; - LLUUID mTrackingID; - LLUUID mWorldID; - bool mValid; - LLSD mLastModified; - EExtension mExtension; - ELinkStatus mLinkStatus; - S32 mUpdateRetries; - LLLocalTextureChangedSignal mChangedSignal; + LLAvatarAppearanceDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind); + + private: /* private enums */ + enum ELinkStatus + { + LS_ON, + LS_BROKEN, + }; + + enum EExtension + { + ET_IMG_BMP, + ET_IMG_TGA, + ET_IMG_JPG, + ET_IMG_PNG + }; + + private: /* members */ + std::string mFilename; + std::string mShortName; + LLUUID mTrackingID; + LLUUID mWorldID; + bool mValid; + LLSD mLastModified; + EExtension mExtension; + ELinkStatus mLinkStatus; + S32 mUpdateRetries; + LLLocalTextureChangedSignal mChangedSignal; // Store a list of accosiated materials // Might be a better idea to hold this in LLGLTFMaterialList @@ -113,43 +113,43 @@ class LLLocalBitmap class LLLocalBitmapTimer : public LLEventTimer { - public: - LLLocalBitmapTimer(); - ~LLLocalBitmapTimer(); + public: + LLLocalBitmapTimer(); + ~LLLocalBitmapTimer(); - public: - void startTimer(); - void stopTimer(); - bool tick() override; + public: + void startTimer(); + void stopTimer(); + bool tick() override; }; class LLLocalBitmapMgr : public LLSingleton { - LLSINGLETON(LLLocalBitmapMgr); - ~LLLocalBitmapMgr(); + LLSINGLETON(LLLocalBitmapMgr); + ~LLLocalBitmapMgr(); public: bool addUnit(const std::vector& filenames); LLUUID addUnit(const std::string& filename); - void delUnit(LLUUID tracking_id); - bool checkTextureDimensions(std::string filename); + void delUnit(LLUUID tracking_id); + bool checkTextureDimensions(std::string filename); - LLUUID getWorldID(const LLUUID &tracking_id) const; + LLUUID getWorldID(const LLUUID &tracking_id) const; bool isLocal(const LLUUID& world_id) const; - std::string getFilename(const LLUUID &tracking_id) const; + std::string getFilename(const LLUUID &tracking_id) const; boost::signals2::connection setOnChangedCallback(const LLUUID tracking_id, const LLLocalBitmap::LLLocalTextureCallback& cb); void associateGLTFMaterial(const LLUUID tracking_id, LLGLTFMaterial* mat); - void feedScrollList(LLScrollListCtrl* ctrl); - void doUpdates(); - void setNeedsRebake(); - void doRebake(); - + void feedScrollList(LLScrollListCtrl* ctrl); + void doUpdates(); + void setNeedsRebake(); + void doRebake(); + private: - std::list mBitmapList; - LLLocalBitmapTimer mTimer; - bool mNeedsRebake; - typedef std::list::iterator local_list_iter; + std::list mBitmapList; + LLLocalBitmapTimer mTimer; + bool mNeedsRebake; + typedef std::list::iterator local_list_iter; typedef std::list::const_iterator local_list_citer; }; diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index ff54d48602..9c2d1bb287 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -1,25 +1,25 @@ -/** +/** * @file lllocalrendermaterials.h * @brief Local GLTF materials header * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, 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$ */ @@ -43,11 +43,11 @@ public: /* main */ virtual ~LLLocalGLTFMaterial(); public: /* accessors */ - std::string getFilename() const; - std::string getShortName() const; - LLUUID getTrackingID() const; - LLUUID getWorldID() const; - S32 getIndexInFile() const; + std::string getFilename() const; + std::string getShortName() const; + LLUUID getTrackingID() const; + LLUUID getWorldID() const; + S32 getIndexInFile() const; public: bool updateSelf(); diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index 5bf587292d..828c0a0747 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmediadataclient.cpp * @brief class for queueing up requests for media data * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,39 +46,39 @@ // // When making a request -// - obtain the "overall interest score" of the object. -// This would be the sum of the impls' interest scores. -// - put the request onto a queue sorted by this score -// (highest score at the front of the queue) -// - On a timer, once a second, pull off the head of the queue and send -// the request. +// - obtain the "overall interest score" of the object. +// This would be the sum of the impls' interest scores. +// - put the request onto a queue sorted by this score +// (highest score at the front of the queue) +// - On a timer, once a second, pull off the head of the queue and send +// the request. // - Any request that gets a 503 still goes through the retry logic // /*************************************************************************************************************** - What's up with this queueing code? + What's up with this queueing code? - First, a bit of background: + First, a bit of background: - Media on a prim was added into the system in the Viewer 2.0 timeframe. In order to avoid changing the - network format of objects, an unused field in the object (the "MediaURL" string) was repurposed to - indicate that the object had media data, and also hold a sequence number and the UUID of the agent - who last updated the data. The actual media data for objects is accessed via the "ObjectMedia" capability. - Due to concerns about sim performance, requests to this capability are rate-limited to 5 requests every - 5 seconds per agent. + Media on a prim was added into the system in the Viewer 2.0 timeframe. In order to avoid changing the + network format of objects, an unused field in the object (the "MediaURL" string) was repurposed to + indicate that the object had media data, and also hold a sequence number and the UUID of the agent + who last updated the data. The actual media data for objects is accessed via the "ObjectMedia" capability. + Due to concerns about sim performance, requests to this capability are rate-limited to 5 requests every + 5 seconds per agent. - The initial implementation of LLMediaDataClient used a single queue to manage requests to the "ObjectMedia" cap. - Requests to the cap were queued so that objects closer to the avatar were loaded in first, since they were most - likely to be the ones the media performance manager would load. + The initial implementation of LLMediaDataClient used a single queue to manage requests to the "ObjectMedia" cap. + Requests to the cap were queued so that objects closer to the avatar were loaded in first, since they were most + likely to be the ones the media performance manager would load. - This worked in some cases, but we found that it was possible for a scripted object that constantly updated its - media data to starve other objects, since the same queue contained both requests to load previously unseen media - data and requests to fetch media data in response to object updates. + This worked in some cases, but we found that it was possible for a scripted object that constantly updated its + media data to starve other objects, since the same queue contained both requests to load previously unseen media + data and requests to fetch media data in response to object updates. - The solution for this we came up with was to have two queues. The sorted queue contains requests to fetch media - data for objects that don't have it yet, and the round-robin queue contains requests to update media data for - objects that have already completed their initial load. When both queues are non-empty, the code ping-pongs - between them so that updates can't completely block initial load-in. + The solution for this we came up with was to have two queues. The sorted queue contains requests to fetch media + data for objects that don't have it yet, and the round-robin queue contains requests to update media data for + objects that have already completed their initial load. When both queues are non-empty, the code ping-pongs + between them so that updates can't completely block initial load-in. **************************************************************************************************************/ // @@ -98,7 +98,7 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q); //========================================================================= /// Uniary Predicate for matching requests in collections by either the request /// or by UUID -/// +/// class PredicateMatchRequest { public: @@ -121,7 +121,7 @@ PredicateMatchRequest::PredicateMatchRequest(const LLMediaDataClient::Request::p mMatchType(matchType), mId() {} - + PredicateMatchRequest::PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType) : mRequest(), mMatchType(matchType), @@ -145,7 +145,7 @@ bool PredicateMatchRequest::operator()(const LLMediaDataClient::Request::ptr_t & } //========================================================================= -/// +/// template void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred) { @@ -169,7 +169,7 @@ void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred) // ////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay, +LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay, U32 max_retries, U32 max_sorted_queue_size, U32 max_round_robin_queue_size): mQueueTimerDelay(queue_timer_delay), mRetryTimerDelay(retry_timer_delay), @@ -187,12 +187,12 @@ LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_dela LLMediaDataClient::~LLMediaDataClient() { - stopQueueTimer(); + stopQueueTimer(); } bool LLMediaDataClient::isEmpty() const { - return mQueue.empty(); + return mQueue.empty(); } bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) @@ -203,114 +203,114 @@ bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) return true; if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end()) return true; - - return false; + + return false; } void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) { - LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; PredicateMatchRequest upred(object->getID()); mark_dead_and_remove_if(mQueue, upred); mark_dead_and_remove_if(mUnQueuedRequests, upred); } -void LLMediaDataClient::startQueueTimer() +void LLMediaDataClient::startQueueTimer() { - if (! mQueueTimerIsRunning) - { - LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL; - // LLEventTimer automagically takes care of the lifetime of this object - new QueueTimer(mQueueTimerDelay, this); - } - else { - LL_DEBUGS("LLMediaDataClient") << "queue timer is already running" << LL_ENDL; - } + if (! mQueueTimerIsRunning) + { + LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL; + // LLEventTimer automagically takes care of the lifetime of this object + new QueueTimer(mQueueTimerDelay, this); + } + else { + LL_DEBUGS("LLMediaDataClient") << "queue timer is already running" << LL_ENDL; + } } void LLMediaDataClient::stopQueueTimer() { - mQueueTimerIsRunning = false; + mQueueTimerIsRunning = false; } bool LLMediaDataClient::processQueueTimer() { if (isDoneProcessing()) - return true; + return true; + + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is: " << mQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mQueue << LL_ENDL; - LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is: " << mQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mQueue << LL_ENDL; - - serviceQueue(); + serviceQueue(); serviceHttp(); - LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is: " << mQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mQueue << LL_ENDL; - + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is: " << mQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mQueue << LL_ENDL; + return isDoneProcessing(); } LLMediaDataClient::Request::ptr_t LLMediaDataClient::dequeue() { - Request::ptr_t request; - request_queue_t *queue_p = getQueue(); - - if (queue_p->empty()) - { - LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL; - } - else - { - request = queue_p->front(); - - if(canServiceRequest(request)) - { - // We will be returning this request, so remove it from the queue. - queue_p->pop_front(); - } - else - { - // Don't return this request -- it's not ready to be serviced. + Request::ptr_t request; + request_queue_t *queue_p = getQueue(); + + if (queue_p->empty()) + { + LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL; + } + else + { + request = queue_p->front(); + + if(canServiceRequest(request)) + { + // We will be returning this request, so remove it from the queue. + queue_p->pop_front(); + } + else + { + // Don't return this request -- it's not ready to be serviced. request.reset(); - } - } + } + } - return request; + return request; } void LLMediaDataClient::pushBack(Request::ptr_t request) { - request_queue_t *queue_p = getQueue(); - queue_p->push_front(request); + request_queue_t *queue_p = getQueue(); + queue_p->push_front(request); } void LLMediaDataClient::trackRequest(Request::ptr_t request) { - request_set_t::iterator iter = mUnQueuedRequests.find(request); - - if(iter != mUnQueuedRequests.end()) - { - LL_WARNS("LLMediaDataClient") << "Tracking already tracked request: " << *request << LL_ENDL; - } - else - { - mUnQueuedRequests.insert(request); - } + request_set_t::iterator iter = mUnQueuedRequests.find(request); + + if(iter != mUnQueuedRequests.end()) + { + LL_WARNS("LLMediaDataClient") << "Tracking already tracked request: " << *request << LL_ENDL; + } + else + { + mUnQueuedRequests.insert(request); + } } void LLMediaDataClient::stopTrackingRequest(Request::ptr_t request) { - request_set_t::iterator iter = mUnQueuedRequests.find(request); - - if (iter != mUnQueuedRequests.end()) - { - mUnQueuedRequests.erase(iter); - } - else - { - LL_WARNS("LLMediaDataClient") << "Removing an untracked request: " << *request << LL_ENDL; - } + request_set_t::iterator iter = mUnQueuedRequests.find(request); + + if (iter != mUnQueuedRequests.end()) + { + mUnQueuedRequests.erase(iter); + } + else + { + LL_WARNS("LLMediaDataClient") << "Removing an untracked request: " << *request << LL_ENDL; + } } bool LLMediaDataClient::isDoneProcessing() const @@ -320,39 +320,39 @@ bool LLMediaDataClient::isDoneProcessing() const void LLMediaDataClient::serviceQueue() -{ - // Peel one off of the items from the queue and execute it - Request::ptr_t request; - - do - { - request = dequeue(); - - if(!request) - { - // Queue is empty. - return; - } - - if(request->isDead()) - { - LL_INFOS("LLMediaDataClient") << "Skipping dead request " << *request << LL_ENDL; - continue; - } - - } while(false); - - // try to send the HTTP message to the cap url - std::string url = request->getCapability(); - if (!url.empty()) - { - const LLSD &sd_payload = request->getPayload(); - LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL; - - // Add this request to the non-queued tracking list - trackRequest(request); - - // and make the post +{ + // Peel one off of the items from the queue and execute it + Request::ptr_t request; + + do + { + request = dequeue(); + + if(!request) + { + // Queue is empty. + return; + } + + if(request->isDead()) + { + LL_INFOS("LLMediaDataClient") << "Skipping dead request " << *request << LL_ENDL; + continue; + } + + } while(false); + + // try to send the HTTP message to the cap url + std::string url = request->getCapability(); + if (!url.empty()) + { + const LLSD &sd_payload = request->getPayload(); + LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL; + + // Add this request to the non-queued tracking list + trackRequest(request); + + // and make the post LLCore::HttpHandler::ptr_t handler = request->createHandler(); LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, mHttpPolicy, url, sd_payload, mHttpOpts, mHttpHeaders, handler); @@ -363,25 +363,25 @@ void LLMediaDataClient::serviceQueue() LL_WARNS("LLMediaDataClient") << "'" << url << "' request POST failed. Reason " << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL; } - } - else - { - // Cap url doesn't exist. - - if(request->getRetryCount() < mMaxNumRetries) - { - LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " (empty cap url), will retry." << LL_ENDL; - // Put this request back at the head of its queue, and retry next time the queue timer fires. - request->incRetryCount(); - pushBack(request); - } - else - { - // This request has exceeded its maximum retry count. It will be dropped. - LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL; - } - - } + } + else + { + // Cap url doesn't exist. + + if(request->getRetryCount() < mMaxNumRetries) + { + LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " (empty cap url), will retry." << LL_ENDL; + // Put this request back at the head of its queue, and retry next time the queue timer fires. + request->incRetryCount(); + pushBack(request); + } + else + { + // This request has exceeded its maximum retry count. It will be dropped. + LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL; + } + + } } void LLMediaDataClient::serviceHttp() @@ -392,16 +392,16 @@ void LLMediaDataClient::serviceHttp() // dump the queue std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q) { - int i = 0; - LLMediaDataClient::request_queue_t::const_iterator iter = q.begin(); - LLMediaDataClient::request_queue_t::const_iterator end = q.end(); - while (iter != end) - { - s << "\t" << i << "]: " << (*iter)->getID().asString() << "(" << (*iter)->getObject()->getMediaInterest() << ")"; - iter++; - i++; - } - return s; + int i = 0; + LLMediaDataClient::request_queue_t::const_iterator iter = q.begin(); + LLMediaDataClient::request_queue_t::const_iterator end = q.end(); + while (iter != end) + { + s << "\t" << i << "]: " << (*iter)->getID().asString() << "(" << (*iter)->getObject()->getMediaInterest() << ")"; + iter++; + i++; + } + return s; } ////////////////////////////////////////////////////////////////////////////////////// @@ -414,27 +414,27 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc) : LLEventTimer(time), mMDC(mdc) { - mMDC->setIsRunning(true); + mMDC->setIsRunning(true); } // virtual bool LLMediaDataClient::QueueTimer::tick() { - bool result = TRUE; + bool result = TRUE; - if (!mMDC.isNull()) - { - result = mMDC->processQueueTimer(); - - if(result) - { - // This timer won't fire again. - mMDC->setIsRunning(false); - mMDC = NULL; - } - } + if (!mMDC.isNull()) + { + result = mMDC->processQueueTimer(); - return result; + if(result) + { + // This timer won't fire again. + mMDC->setIsRunning(false); + mMDC = NULL; + } + } + + return result; } @@ -447,29 +447,29 @@ bool LLMediaDataClient::QueueTimer::tick() LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request) : LLEventTimer(time), mRequest(request) { - mRequest->startTracking(); + mRequest->startTracking(); } // virtual bool LLMediaDataClient::RetryTimer::tick() { - mRequest->stopTracking(); + mRequest->stopTracking(); - if(mRequest->isDead()) - { - LL_INFOS("LLMediaDataClient") << "RetryTimer fired for dead request: " << *mRequest << ", aborting." << LL_ENDL; - } - else - { - LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *mRequest << ", retrying." << LL_ENDL; - mRequest->reEnqueue(); - } + if(mRequest->isDead()) + { + LL_INFOS("LLMediaDataClient") << "RetryTimer fired for dead request: " << *mRequest << ", aborting." << LL_ENDL; + } + else + { + LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *mRequest << ", retrying." << LL_ENDL; + mRequest->reEnqueue(); + } - // Release the ref to the request. - mRequest.reset(); + // Release the ref to the request. + mRequest.reset(); - // Don't fire again - return true; + // Don't fire again + return true; } @@ -481,124 +481,124 @@ bool LLMediaDataClient::RetryTimer::tick() /*static*/U32 LLMediaDataClient::Request::sNum = 0; LLMediaDataClient::Request::Request(Type in_type, - LLMediaDataClientObject *obj, - LLMediaDataClient *mdc, - S32 face) + LLMediaDataClientObject *obj, + LLMediaDataClient *mdc, + S32 face) : mType(in_type), mObject(obj), - mNum(++sNum), + mNum(++sNum), mRetryCount(0), mMDC(mdc), mScore((F64)0.0), mFace(face) { - mObjectID = mObject->getID(); + mObjectID = mObject->getID(); } const char *LLMediaDataClient::Request::getCapName() const { - if(mMDC) - return mMDC->getCapabilityName(); - - return ""; + if(mMDC) + return mMDC->getCapabilityName(); + + return ""; } std::string LLMediaDataClient::Request::getCapability() const { - if(mMDC) - { - return getObject()->getCapabilityUrl(getCapName()); - } - - return ""; + if(mMDC) + { + return getObject()->getCapabilityUrl(getCapName()); + } + + return ""; } const char *LLMediaDataClient::Request::getTypeAsString() const { - Type t = getType(); - switch (t) - { - case GET: - return "GET"; - break; - case UPDATE: - return "UPDATE"; - break; - case NAVIGATE: - return "NAVIGATE"; - break; - case ANY: - return "ANY"; - break; - } - return ""; + Type t = getType(); + switch (t) + { + case GET: + return "GET"; + break; + case UPDATE: + return "UPDATE"; + break; + case NAVIGATE: + return "NAVIGATE"; + break; + case ANY: + return "ANY"; + break; + } + return ""; } void LLMediaDataClient::Request::reEnqueue() { - if(mMDC) - { - mMDC->enqueue(shared_from_this()); - } + if(mMDC) + { + mMDC->enqueue(shared_from_this()); + } } F32 LLMediaDataClient::Request::getRetryTimerDelay() const { - if(mMDC) - return mMDC->mRetryTimerDelay; - - return 0.0f; + if(mMDC) + return mMDC->mRetryTimerDelay; + + return 0.0f; } U32 LLMediaDataClient::Request::getMaxNumRetries() const { - if(mMDC) - return mMDC->mMaxNumRetries; - - return 0; + if(mMDC) + return mMDC->mMaxNumRetries; + + return 0; } void LLMediaDataClient::Request::updateScore() -{ - F64 tmp = mObject->getMediaInterest(); - if (tmp != mScore) - { - LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL; - mScore = tmp; - } +{ + F64 tmp = mObject->getMediaInterest(); + if (tmp != mScore) + { + LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL; + mScore = tmp; + } } - -void LLMediaDataClient::Request::markDead() -{ - mMDC = NULL; + +void LLMediaDataClient::Request::markDead() +{ + mMDC = NULL; } -bool LLMediaDataClient::Request::isDead() -{ - return ((mMDC == NULL) || mObject->isDead()); +bool LLMediaDataClient::Request::isDead() +{ + return ((mMDC == NULL) || mObject->isDead()); } -void LLMediaDataClient::Request::startTracking() -{ - if(mMDC) +void LLMediaDataClient::Request::startTracking() +{ + if(mMDC) mMDC->trackRequest(shared_from_this()); } -void LLMediaDataClient::Request::stopTracking() -{ - if(mMDC) +void LLMediaDataClient::Request::stopTracking() +{ + if(mMDC) mMDC->stopTrackingRequest(shared_from_this()); } std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) { - s << "request: num=" << r.getNum() - << " type=" << r.getTypeAsString() - << " ID=" << r.getID() - << " face=" << r.getFace() - << " #retries=" << r.getRetryCount(); - return s; + s << "request: num=" << r.getNum() + << " type=" << r.getTypeAsString() + << " ID=" << r.getID() + << " face=" << r.getFace() + << " #retries=" << r.getRetryCount(); + return s; } //======================================================================== @@ -634,7 +634,7 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo mRequest->incRetryCount(); - if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) + if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) { LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; @@ -642,9 +642,9 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo // InstanceTracker<> and LLEventTimer) new RetryTimer(F32(retry_timeout/*secs*/), mRequest); } - else + else { - LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " + LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; } } @@ -664,223 +664,223 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object) { - // Create a get request and put it in the queue. - enqueue(Request::ptr_t(new RequestGet(object, this))); + // Create a get request and put it in the queue. + enqueue(Request::ptr_t(new RequestGet(object, this))); } -const char *LLObjectMediaDataClient::getCapabilityName() const +const char *LLObjectMediaDataClient::getCapabilityName() const { - return "ObjectMedia"; + return "ObjectMedia"; } LLObjectMediaDataClient::request_queue_t *LLObjectMediaDataClient::getQueue() { - return (mCurrentQueueIsTheSortedQueue) ? &mQueue : &mRoundRobinQueue; + return (mCurrentQueueIsTheSortedQueue) ? &mQueue : &mRoundRobinQueue; } void LLObjectMediaDataClient::sortQueue() { - if(!mQueue.empty()) - { - // score all elements in the sorted queue. - for(request_queue_t::iterator iter = mQueue.begin(); iter != mQueue.end(); iter++) - { - (*iter)->updateScore(); - } - - // Re-sort the list... - mQueue.sort(compareRequestScores); - - // ...then cull items over the max - U32 size = mQueue.size(); - if (size > mMaxSortedQueueSize) - { - U32 num_to_cull = (size - mMaxSortedQueueSize); - LL_INFOS_ONCE("LLMediaDataClient") << "sorted queue MAXED OUT! Culling " - << num_to_cull << " items" << LL_ENDL; - while (num_to_cull-- > 0) - { - mQueue.back()->markDead(); - mQueue.pop_back(); - } - } - } - + if(!mQueue.empty()) + { + // score all elements in the sorted queue. + for(request_queue_t::iterator iter = mQueue.begin(); iter != mQueue.end(); iter++) + { + (*iter)->updateScore(); + } + + // Re-sort the list... + mQueue.sort(compareRequestScores); + + // ...then cull items over the max + U32 size = mQueue.size(); + if (size > mMaxSortedQueueSize) + { + U32 num_to_cull = (size - mMaxSortedQueueSize); + LL_INFOS_ONCE("LLMediaDataClient") << "sorted queue MAXED OUT! Culling " + << num_to_cull << " items" << LL_ENDL; + while (num_to_cull-- > 0) + { + mQueue.back()->markDead(); + mQueue.pop_back(); + } + } + } + } // static bool LLObjectMediaDataClient::compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2) { - if (!o2) return true; - if (!o1) return false; - return ( o1->getScore() > o2->getScore() ); + if (!o2) return true; + if (!o1) return false; + return ( o1->getScore() > o2->getScore() ); } void LLObjectMediaDataClient::enqueue(Request::ptr_t request) { - static LLCachedControl audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); - if (!audio_streaming_enabled) - { - LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; - return; - } - - if(request->isDead()) - { - LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL; - return; - } - - // Invariants: - // new requests always go into the sorted queue. - // - - bool is_new = request->isNew(); - - if(!is_new && (request->getType() == Request::GET)) - { - // For GET requests that are not new, if a matching request is already in the round robin queue, - // in flight, or being retried, leave it at its current position. + static LLCachedControl audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); + if (!audio_streaming_enabled) + { + LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; + return; + } + + if(request->isDead()) + { + LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL; + return; + } + + // Invariants: + // new requests always go into the sorted queue. + // + + bool is_new = request->isNew(); + + if(!is_new && (request->getType() == Request::GET)) + { + // For GET requests that are not new, if a matching request is already in the round robin queue, + // in flight, or being retried, leave it at its current position. PredicateMatchRequest upred(request->getID(), Request::GET); request_queue_t::iterator iter = std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), upred); request_set_t::iterator iter2 = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); - if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) ) - { - LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; - - return; - } - } - - // TODO: should an UPDATE cause pending GET requests for the same object to be removed from the queue? - // IF the update will cause an object update message to be sent out at some point in the future, it probably should. - - // Remove any existing requests of this type for this object + if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) ) + { + LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; + + return; + } + } + + // TODO: should an UPDATE cause pending GET requests for the same object to be removed from the queue? + // IF the update will cause an object update message to be sent out at some point in the future, it probably should. + + // Remove any existing requests of this type for this object PredicateMatchRequest upred(request->getID(), request->getType()); mark_dead_and_remove_if(mQueue, upred); mark_dead_and_remove_if(mRoundRobinQueue, upred); mark_dead_and_remove_if(mUnQueuedRequests, upred); - if (is_new) - { - LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL; - - mQueue.push_back(request); - - LL_DEBUGS("LLMediaDataClientQueue") << "SORTED queue:" << mQueue << LL_ENDL; - } - else - { - if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize) - { - LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL; - LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL; - return; - } - - LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL; - // Push the request on the pending queue - mRoundRobinQueue.push_back(request); - - LL_DEBUGS("LLMediaDataClientQueue") << "RR queue:" << mRoundRobinQueue << LL_ENDL; - } - // Start the timer if not already running - startQueueTimer(); -} - -bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request) -{ - if(mCurrentQueueIsTheSortedQueue) - { - if(!request->getObject()->isInterestingEnough()) - { - LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL; - return false; - } - } - - return true; + if (is_new) + { + LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL; + + mQueue.push_back(request); + + LL_DEBUGS("LLMediaDataClientQueue") << "SORTED queue:" << mQueue << LL_ENDL; + } + else + { + if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize) + { + LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL; + return; + } + + LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL; + // Push the request on the pending queue + mRoundRobinQueue.push_back(request); + + LL_DEBUGS("LLMediaDataClientQueue") << "RR queue:" << mRoundRobinQueue << LL_ENDL; + } + // Start the timer if not already running + startQueueTimer(); +} + +bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request) +{ + if(mCurrentQueueIsTheSortedQueue) + { + if(!request->getObject()->isInterestingEnough()) + { + LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL; + return false; + } + } + + return true; }; void LLObjectMediaDataClient::swapCurrentQueue() { - // Swap - mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; - // If its empty, swap back - if (getQueue()->empty()) - { - mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; - } + // Swap + mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; + // If its empty, swap back + if (getQueue()->empty()) + { + mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; + } } bool LLObjectMediaDataClient::isEmpty() const { - return mQueue.empty() && mRoundRobinQueue.empty(); + return mQueue.empty() && mRoundRobinQueue.empty(); } bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) { - // First, call parent impl. - if(LLMediaDataClient::isInQueue(object)) - return true; + // First, call parent impl. + if(LLMediaDataClient::isInQueue(object)) + return true; if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end()) return true; - return false; + return false; } void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) { - // First, call parent impl. - LLMediaDataClient::removeFromQueue(object); - + // First, call parent impl. + LLMediaDataClient::removeFromQueue(object); + mark_dead_and_remove_if(mRoundRobinQueue, PredicateMatchRequest(object->getID())); } bool LLObjectMediaDataClient::processQueueTimer() { if (isDoneProcessing()) - return true; - - LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is: " << mQueue.size() - << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; + return true; -// purgeDeadRequests(); + LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is: " << mQueue.size() + << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; - sortQueue(); +// purgeDeadRequests(); - LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is: " << mQueue << LL_ENDL; - - serviceQueue(); + sortQueue(); + + LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is: " << mQueue << LL_ENDL; + + serviceQueue(); serviceHttp(); - swapCurrentQueue(); - - LL_DEBUGS("LLMediaDataClient") << "finished, SORTED queue size is: " << mQueue.size() - << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; - LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; - + swapCurrentQueue(); + + LL_DEBUGS("LLMediaDataClient") << "finished, SORTED queue size is: " << mQueue.size() + << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; + return isDoneProcessing(); } LLObjectMediaDataClient::RequestGet::RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): - LLMediaDataClient::Request(LLMediaDataClient::Request::GET, obj, mdc) + LLMediaDataClient::Request(LLMediaDataClient::Request::GET, obj, mdc) { } LLSD LLObjectMediaDataClient::RequestGet::getPayload() const { - LLSD result; - result["verb"] = "GET"; - result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); - - return result; + LLSD result; + result["verb"] = "GET"; + result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); + + return result; } LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestGet::createHandler() @@ -891,37 +891,37 @@ LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestGet::createHandler() void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object) { - // Create an update request and put it in the queue. - enqueue(Request::ptr_t(new RequestUpdate(object, this))); + // Create an update request and put it in the queue. + enqueue(Request::ptr_t(new RequestUpdate(object, this))); } LLObjectMediaDataClient::RequestUpdate::RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): - LLMediaDataClient::Request(LLMediaDataClient::Request::UPDATE, obj, mdc) + LLMediaDataClient::Request(LLMediaDataClient::Request::UPDATE, obj, mdc) { } LLSD LLObjectMediaDataClient::RequestUpdate::getPayload() const { - LLSD result; - result["verb"] = "UPDATE"; - result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); + LLSD result; + result["verb"] = "UPDATE"; + result[LLTextureEntry::OBJECT_ID_KEY] = mObject->getID(); + + LLSD object_media_data; + int i = 0; + int end = mObject->getMediaDataCount(); + for ( ; i < end ; ++i) + { + object_media_data.append(mObject->getMediaDataLLSD(i)); + } + + result[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; - LLSD object_media_data; - int i = 0; - int end = mObject->getMediaDataCount(); - for ( ; i < end ; ++i) - { - object_media_data.append(mObject->getMediaDataLLSD(i)); - } - - result[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; - - return result; + return result; } LLCore::HttpHandler::ptr_t LLObjectMediaDataClient::RequestUpdate::createHandler() { - // This just uses the base class's responder. + // This just uses the base class's responder. return LLCore::HttpHandler::ptr_t(new LLMediaDataClient::Handler(shared_from_this())); } @@ -947,16 +947,16 @@ void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response if (content.has("error")) { const LLSD &error = content["error"]; - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; // XXX Warn user? } - else + else { // Check the data const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; - if (object_id != getRequest()->getObject()->getID()) + if (object_id != getRequest()->getObject()->getID()) { // NOT good, wrong object id!! LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; @@ -978,87 +978,87 @@ void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response // ////////////////////////////////////////////////////////////////////////////////////// -const char *LLObjectMediaNavigateClient::getCapabilityName() const +const char *LLObjectMediaNavigateClient::getCapabilityName() const { - return "ObjectMediaNavigate"; + return "ObjectMediaNavigate"; } void LLObjectMediaNavigateClient::enqueue(Request::ptr_t request) { - static LLCachedControl audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); - if (!audio_streaming_enabled) - { - LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; - return; - } - - if(request->isDead()) - { - LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL; - return; - } - + static LLCachedControl audio_streaming_enabled(gSavedSettings, "AudioStreamingMedia", true); + if (!audio_streaming_enabled) + { + LL_DEBUGS("LLMediaDataClient") << "not queueing request when Media is disabled " << *request << LL_ENDL; + return; + } + + if(request->isDead()) + { + LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL; + return; + } + PredicateMatchRequest upred(request); - // If there's already a matching request in the queue, remove it. + // If there's already a matching request in the queue, remove it. request_queue_t::iterator iter = std::find_if(mQueue.begin(), mQueue.end(), upred); - if(iter != mQueue.end()) - { - LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; - mQueue.erase(iter); - } - else - { + if(iter != mQueue.end()) + { + LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; + mQueue.erase(iter); + } + else + { request_set_t::iterator set_iter = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); - if(set_iter != mUnQueuedRequests.end()) - { - LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; - mUnQueuedRequests.erase(set_iter); - } - } + if(set_iter != mUnQueuedRequests.end()) + { + LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; + mUnQueuedRequests.erase(set_iter); + } + } #if 0 - // Sadly, this doesn't work. It ends up creating a race condition when the user navigates and then hits the "back" button - // where the navigate-back appears to be spurious and doesn't get broadcast. - if(request->getObject()->isCurrentMediaUrl(request->getFace(), request->getURL())) - { - // This navigate request is trying to send the face to the current URL. Drop it. - LL_DEBUGS("LLMediaDataClient") << "dropping spurious request " << (*request) << LL_ENDL; - } - else + // Sadly, this doesn't work. It ends up creating a race condition when the user navigates and then hits the "back" button + // where the navigate-back appears to be spurious and doesn't get broadcast. + if(request->getObject()->isCurrentMediaUrl(request->getFace(), request->getURL())) + { + // This navigate request is trying to send the face to the current URL. Drop it. + LL_DEBUGS("LLMediaDataClient") << "dropping spurious request " << (*request) << LL_ENDL; + } + else #endif - { - LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL; - mQueue.push_back(request); - - // Start the timer if not already running - startQueueTimer(); - } + { + LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL; + mQueue.push_back(request); + + // Start the timer if not already running + startQueueTimer(); + } } void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url) { -// LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL; - - // Create a get request and put it in the queue. - enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url))); +// LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL; + + // Create a get request and put it in the queue. + enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url))); } LLObjectMediaNavigateClient::RequestNavigate::RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url): - LLMediaDataClient::Request(LLMediaDataClient::Request::NAVIGATE, obj, mdc, (S32)texture_index), - mURL(url) + LLMediaDataClient::Request(LLMediaDataClient::Request::NAVIGATE, obj, mdc, (S32)texture_index), + mURL(url) { } LLSD LLObjectMediaNavigateClient::RequestNavigate::getPayload() const { - LLSD result; - result[LLTextureEntry::OBJECT_ID_KEY] = getID(); - result[LLMediaEntry::CURRENT_URL_KEY] = mURL; - result[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)getFace(); - - return result; + LLSD result; + result[LLTextureEntry::OBJECT_ID_KEY] = getID(); + result[LLMediaEntry::CURRENT_URL_KEY] = mURL; + result[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)getFace(); + + return result; } LLCore::HttpHandler::ptr_t LLObjectMediaNavigateClient::RequestNavigate::createHandler() @@ -1121,7 +1121,7 @@ void LLObjectMediaNavigateClient::Handler::mediaNavigateBounceBack() { LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating or denied." << LL_ENDL; const LLSD &payload = getRequest()->getPayload(); - + // bounce the face back getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 428e85b976..a5f20e51db 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -1,25 +1,25 @@ -/** +/** * @file llmediadataclient.h * @brief class for queueing up requests to the media service * * $LicenseInfo:firstyear=2007&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$ */ @@ -41,35 +41,35 @@ class LLMediaDataClientObject : public LLRefCount { public: - // Get the number of media data items - virtual U8 getMediaDataCount() const = 0; - // Get the media data at index, as an LLSD - virtual LLSD getMediaDataLLSD(U8 index) const = 0; - // Return true if the current URL for the face in the media data matches the specified URL. - virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const = 0; - // Get this object's UUID - virtual LLUUID getID() const = 0; - // Navigate back to previous URL - virtual void mediaNavigateBounceBack(U8 index) = 0; - // Does this object have media? - virtual bool hasMedia() const = 0; - // Update the object's media data to the given array - virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0; - // Return the total "interest" of the media (on-screen area) - virtual F64 getMediaInterest() const = 0; - // Return the given cap url - virtual std::string getCapabilityUrl(const std::string &name) const = 0; - // Return whether the object has been marked dead - virtual bool isDead() const = 0; - // Returns a media version number for the object - virtual U32 getMediaVersion() const = 0; - // Returns whether the object is "interesting enough" to fetch - virtual bool isInterestingEnough() const = 0; - // Returns whether we've seen this object yet or not - virtual bool isNew() const = 0; - - // smart pointer - typedef LLPointer ptr_t; + // Get the number of media data items + virtual U8 getMediaDataCount() const = 0; + // Get the media data at index, as an LLSD + virtual LLSD getMediaDataLLSD(U8 index) const = 0; + // Return true if the current URL for the face in the media data matches the specified URL. + virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const = 0; + // Get this object's UUID + virtual LLUUID getID() const = 0; + // Navigate back to previous URL + virtual void mediaNavigateBounceBack(U8 index) = 0; + // Does this object have media? + virtual bool hasMedia() const = 0; + // Update the object's media data to the given array + virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0; + // Return the total "interest" of the media (on-screen area) + virtual F64 getMediaInterest() const = 0; + // Return the given cap url + virtual std::string getCapabilityUrl(const std::string &name) const = 0; + // Return whether the object has been marked dead + virtual bool isDead() const = 0; + // Returns a media version number for the object + virtual U32 getMediaVersion() const = 0; + // Returns whether the object is "interesting enough" to fetch + virtual bool isInterestingEnough() const = 0; + // Returns whether we've seen this object yet or not + virtual bool isNew() const = 0; + + // smart pointer + typedef LLPointer ptr_t; }; @@ -82,40 +82,40 @@ class LLMediaDataClient : public LLRefCount protected: LOG_CLASS(LLMediaDataClient); public: - + const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s) - const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs - const static U32 MAX_RETRIES;// = 4; - const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000; - const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000; - - // Constructor - LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, - F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, - U32 max_retries = MAX_RETRIES, - U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, - U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE); - - F32 getRetryTimerDelay() const { return mRetryTimerDelay; } - - // Returns true iff the queue is empty - virtual bool isEmpty() const; - - // Returns true iff the given object is in the queue - virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); - - // Remove the given object from the queue. Returns true iff the given object is removed. - virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); - - // Called only by the Queue timer and tests (potentially) - virtual bool processQueueTimer(); - + const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs + const static U32 MAX_RETRIES;// = 4; + const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000; + const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000; + + // Constructor + LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE); + + F32 getRetryTimerDelay() const { return mRetryTimerDelay; } + + // Returns true iff the queue is empty + virtual bool isEmpty() const; + + // Returns true iff the given object is in the queue + virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); + + // Remove the given object from the queue. Returns true iff the given object is removed. + virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); + + // Called only by the Queue timer and tests (potentially) + virtual bool processQueueTimer(); + protected: - // Destructor - virtual ~LLMediaDataClient(); // use unref - - // Request (pure virtual base class for requests in the queue) - class Request: + // Destructor + virtual ~LLMediaDataClient(); // use unref + + // Request (pure virtual base class for requests in the queue) + class Request: public std::enable_shared_from_this { public: @@ -138,66 +138,66 @@ protected: virtual ~Request() { } - protected: - // The only way to create one of these is through a subclass. - Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1); - public: - LLMediaDataClientObject *getObject() const { return mObject; } + protected: + // The only way to create one of these is through a subclass. + Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1); + public: + LLMediaDataClientObject *getObject() const { return mObject; } U32 getNum() const { return mNum; } - U32 getRetryCount() const { return mRetryCount; } - void incRetryCount() { mRetryCount++; } + U32 getRetryCount() const { return mRetryCount; } + void incRetryCount() { mRetryCount++; } Type getType() const { return mType; } - F64 getScore() const { return mScore; } - - // Note: may return empty string! - std::string getCapability() const; - const char *getCapName() const; - const char *getTypeAsString() const; - - // Re-enqueue thyself - void reEnqueue(); - - F32 getRetryTimerDelay() const; - U32 getMaxNumRetries() const; - - bool isObjectValid() const { return mObject.notNull() && (!mObject->isDead()); } - bool isNew() const { return isObjectValid() && mObject->isNew(); } - void updateScore(); - - void markDead(); - bool isDead(); - void startTracking(); - void stopTracking(); - - friend std::ostream& operator<<(std::ostream &s, const Request &q); - - const LLUUID &getID() const { return mObjectID; } - S32 getFace() const { return mFace; } - - bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const - { - return ((match_type == ANY) || (mType == other->mType)) && - (mFace == other->mFace) && - (mObjectID == other->mObjectID); - } - protected: - LLMediaDataClientObject::ptr_t mObject; - private: - Type mType; - // Simple tracking - U32 mNum; - static U32 sNum; + F64 getScore() const { return mScore; } + + // Note: may return empty string! + std::string getCapability() const; + const char *getCapName() const; + const char *getTypeAsString() const; + + // Re-enqueue thyself + void reEnqueue(); + + F32 getRetryTimerDelay() const; + U32 getMaxNumRetries() const; + + bool isObjectValid() const { return mObject.notNull() && (!mObject->isDead()); } + bool isNew() const { return isObjectValid() && mObject->isNew(); } + void updateScore(); + + void markDead(); + bool isDead(); + void startTracking(); + void stopTracking(); + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + + const LLUUID &getID() const { return mObjectID; } + S32 getFace() const { return mFace; } + + bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const + { + return ((match_type == ANY) || (mType == other->mType)) && + (mFace == other->mFace) && + (mObjectID == other->mObjectID); + } + protected: + LLMediaDataClientObject::ptr_t mObject; + private: + Type mType; + // Simple tracking + U32 mNum; + static U32 sNum; U32 mRetryCount; - F64 mScore; - - LLUUID mObjectID; - S32 mFace; + F64 mScore; + + LLUUID mObjectID; + S32 mFace; - // Back pointer to the MDC...not a ref! - LLMediaDataClient *mMDC; - }; - //typedef LLPointer request_ptr_t; + // Back pointer to the MDC...not a ref! + LLMediaDataClient *mMDC; + }; + //typedef LLPointer request_ptr_t; class Handler : public LLHttpSDHandler { @@ -215,60 +215,60 @@ protected: }; - class RetryTimer : public LLEventTimer - { - public: - RetryTimer(F32 time, Request::ptr_t); - virtual bool tick() override; - private: - // back-pointer - Request::ptr_t mRequest; - }; + class RetryTimer : public LLEventTimer + { + public: + RetryTimer(F32 time, Request::ptr_t); + virtual bool tick() override; + private: + // back-pointer + Request::ptr_t mRequest; + }; protected: - typedef std::list request_queue_t; - typedef std::set request_set_t; + typedef std::list request_queue_t; + typedef std::set request_set_t; - // Subclasses must override to return a cap name - virtual const char *getCapabilityName() const = 0; + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const = 0; - // Puts the request into a queue, appropriately handling duplicates, etc. + // Puts the request into a queue, appropriately handling duplicates, etc. virtual void enqueue(Request::ptr_t) = 0; - - virtual void serviceQueue(); + + virtual void serviceQueue(); virtual void serviceHttp(); - virtual request_queue_t *getQueue() { return &mQueue; }; + virtual request_queue_t *getQueue() { return &mQueue; }; - // Gets the next request, removing it from the queue - virtual Request::ptr_t dequeue(); - - virtual bool canServiceRequest(Request::ptr_t request) { return true; }; + // Gets the next request, removing it from the queue + virtual Request::ptr_t dequeue(); - // Returns a request to the head of the queue (should only be used for requests that came from dequeue - virtual void pushBack(Request::ptr_t request); - - void trackRequest(Request::ptr_t request); - void stopTrackingRequest(Request::ptr_t request); + virtual bool canServiceRequest(Request::ptr_t request) { return true; }; + + // Returns a request to the head of the queue (should only be used for requests that came from dequeue + virtual void pushBack(Request::ptr_t request); + + void trackRequest(Request::ptr_t request); + void stopTrackingRequest(Request::ptr_t request); bool isDoneProcessing() const; - - request_queue_t mQueue; - - const F32 mQueueTimerDelay; - const F32 mRetryTimerDelay; - const U32 mMaxNumRetries; - const U32 mMaxSortedQueueSize; - const U32 mMaxRoundRobinQueueSize; - - // Set for keeping track of requests that aren't in either queue. This includes: - // Requests that have been sent and are awaiting a response (pointer held by the Responder) - // Requests that are waiting for their retry timers to fire (pointer held by the retry timer) - request_set_t mUnQueuedRequests; - - void startQueueTimer(); - void stopQueueTimer(); + + request_queue_t mQueue; + + const F32 mQueueTimerDelay; + const F32 mRetryTimerDelay; + const U32 mMaxNumRetries; + const U32 mMaxSortedQueueSize; + const U32 mMaxRoundRobinQueueSize; + + // Set for keeping track of requests that aren't in either queue. This includes: + // Requests that have been sent and are awaiting a response (pointer held by the Responder) + // Requests that are waiting for their retry timers to fire (pointer held by the retry timer) + request_set_t mUnQueuedRequests; + + void startQueueTimer(); + void stopQueueTimer(); LLCore::HttpRequest::ptr_t mHttpRequest; LLCore::HttpHeaders::ptr_t mHttpHeaders; @@ -276,29 +276,29 @@ protected: LLCore::HttpRequest::policy_t mHttpPolicy; private: - - static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); - - friend std::ostream& operator<<(std::ostream &s, const Request &q); - friend std::ostream& operator<<(std::ostream &s, const request_queue_t &q); - - class QueueTimer : public LLEventTimer - { - public: - QueueTimer(F32 time, LLMediaDataClient *mdc); - bool tick() override; - private: - // back-pointer - LLPointer mMDC; - }; - - void setIsRunning(bool val) { mQueueTimerIsRunning = val; } - - bool mQueueTimerIsRunning; - -// template friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); -// template friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); -// template friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); + + static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + friend std::ostream& operator<<(std::ostream &s, const request_queue_t &q); + + class QueueTimer : public LLEventTimer + { + public: + QueueTimer(F32 time, LLMediaDataClient *mdc); + bool tick() override; + private: + // back-pointer + LLPointer mMDC; + }; + + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } + + bool mQueueTimerIsRunning; + +// template friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); +// template friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); +// template friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); }; // MediaDataClient specific for the ObjectMedia cap @@ -308,55 +308,55 @@ protected: LOG_CLASS(LLObjectMediaDataClient); public: LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, - F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, - U32 max_retries = MAX_RETRIES, - U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, - U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) - : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries), - mCurrentQueueIsTheSortedQueue(true) - {} - - void fetchMedia(LLMediaDataClientObject *object); + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries), + mCurrentQueueIsTheSortedQueue(true) + {} + + void fetchMedia(LLMediaDataClientObject *object); void updateMedia(LLMediaDataClientObject *object); - class RequestGet: public Request - { - public: - RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); - /*virtual*/ LLSD getPayload() const; + class RequestGet: public Request + { + public: + RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); + /*virtual*/ LLSD getPayload() const; /*virtual*/ LLCore::HttpHandler::ptr_t createHandler(); - }; + }; - class RequestUpdate: public Request - { - public: - RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); - /*virtual*/ LLSD getPayload() const; + class RequestUpdate: public Request + { + public: + RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); + /*virtual*/ LLSD getPayload() const; /*virtual*/ LLCore::HttpHandler::ptr_t createHandler(); - }; + }; + + // Returns true iff the queue is empty + virtual bool isEmpty() const; - // Returns true iff the queue is empty - virtual bool isEmpty() const; - - // Returns true iff the given object is in the queue - virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); - - // Remove the given object from the queue. Returns true iff the given object is removed. - virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); + // Returns true iff the given object is in the queue + virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object); - virtual bool processQueueTimer(); + // Remove the given object from the queue. Returns true iff the given object is removed. + virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object); - virtual bool canServiceRequest(Request::ptr_t request); + virtual bool processQueueTimer(); + + virtual bool canServiceRequest(Request::ptr_t request); protected: - // Subclasses must override to return a cap name - virtual const char *getCapabilityName() const; - - virtual request_queue_t *getQueue(); - - // Puts the request into the appropriate queue - virtual void enqueue(Request::ptr_t); - + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; + + virtual request_queue_t *getQueue(); + + // Puts the request into the appropriate queue + virtual void enqueue(Request::ptr_t); + class Handler: public LLMediaDataClient::Handler { LOG_CLASS(Handler); @@ -370,15 +370,15 @@ protected: }; private: - // The Get/Update data client needs a second queue to avoid object updates starving load-ins. - void swapCurrentQueue(); - - request_queue_t mRoundRobinQueue; - bool mCurrentQueueIsTheSortedQueue; - - // Comparator for sorting - static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2); - void sortQueue(); + // The Get/Update data client needs a second queue to avoid object updates starving load-ins. + void swapCurrentQueue(); + + request_queue_t mRoundRobinQueue; + bool mCurrentQueueIsTheSortedQueue; + + // Comparator for sorting + static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2); + void sortQueue(); }; @@ -388,36 +388,36 @@ class LLObjectMediaNavigateClient : public LLMediaDataClient protected: LOG_CLASS(LLObjectMediaNavigateClient); public: - // NOTE: from llmediaservice.h - static const int ERROR_PERMISSION_DENIED_CODE = 8002; - + // NOTE: from llmediaservice.h + static const int ERROR_PERMISSION_DENIED_CODE = 8002; + LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, - F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, - U32 max_retries = MAX_RETRIES, - U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, - U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) - : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) - {} - + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) + {} + void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url); - // Puts the request into the appropriate queue + // Puts the request into the appropriate queue virtual void enqueue(Request::ptr_t); - class RequestNavigate: public Request - { - public: - RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url); - /*virtual*/ LLSD getPayload() const; + class RequestNavigate: public Request + { + public: + RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url); + /*virtual*/ LLSD getPayload() const; /*virtual*/ LLCore::HttpHandler::ptr_t createHandler(); - /*virtual*/ std::string getURL() { return mURL; } - private: - std::string mURL; - }; - + /*virtual*/ std::string getURL() { return mURL; } + private: + std::string mURL; + }; + protected: - // Subclasses must override to return a cap name - virtual const char *getCapabilityName() const; + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; class Handler : public LLMediaDataClient::Handler { diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index b342fa5549..163fb5ffd4 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanelpeople.cpp * @brief Side tray "People" panel * * $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$ */ @@ -52,7 +52,7 @@ #include "llavatarlist.h" #include "llavatarlistitem.h" #include "llavatarnamecache.h" -#include "llcallingcard.h" // for LLAvatarTracker +#include "llcallingcard.h" // for LLAvatarTracker #include "llcallbacklist.h" #include "llerror.h" #include "llfloateravatarpicker.h" @@ -65,8 +65,8 @@ #include "llparticipantlist.h" #include "llsidetraypanelcontainer.h" #include "llrecentpeople.h" -#include "llviewercontrol.h" // for gSavedSettings -#include "llviewermenu.h" // for gMenuHolder +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewermenu.h" // for gMenuHolder #include "llviewerregion.h" #include "llvoiceclient.h" #include "llworld.h" @@ -76,165 +76,165 @@ #include "llagentui.h" #include "llslurl.h" -#define FRIEND_LIST_UPDATE_TIMEOUT 0.5 +#define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 -static const std::string NEARBY_TAB_NAME = "nearby_panel"; -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 NEARBY_TAB_NAME = "nearby_panel"; +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"; /** Comparator for comparing avatar items by last interaction date */ class LLAvatarItemRecentComparator : public LLAvatarItemComparator { public: - LLAvatarItemRecentComparator() {}; - virtual ~LLAvatarItemRecentComparator() {}; + LLAvatarItemRecentComparator() {}; + virtual ~LLAvatarItemRecentComparator() {}; protected: - virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const - { - LLRecentPeople& people = LLRecentPeople::instance(); - const LLDate& date1 = people.getDate(avatar_item1->getAvatarId()); - const LLDate& date2 = people.getDate(avatar_item2->getAvatarId()); - - //older comes first - return date1 > date2; - } + virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const + { + LLRecentPeople& people = LLRecentPeople::instance(); + const LLDate& date1 = people.getDate(avatar_item1->getAvatarId()); + const LLDate& date2 = people.getDate(avatar_item2->getAvatarId()); + + //older comes first + return date1 > date2; + } }; /** Compares avatar items by online status, then by name */ class LLAvatarItemStatusComparator : public LLAvatarItemComparator { public: - LLAvatarItemStatusComparator() {}; + LLAvatarItemStatusComparator() {}; protected: - /** - * @return true if item1 < item2, false otherwise - */ - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { - LLAvatarTracker& at = LLAvatarTracker::instance(); - bool online1 = at.isBuddyOnline(item1->getAvatarId()); - bool online2 = at.isBuddyOnline(item2->getAvatarId()); - - if (online1 == online2) - { - std::string name1 = item1->getAvatarName(); - std::string name2 = item2->getAvatarName(); - - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); - - return name1 < name2; - } - - return online1 > online2; - } + /** + * @return true if item1 < item2, false otherwise + */ + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { + LLAvatarTracker& at = LLAvatarTracker::instance(); + bool online1 = at.isBuddyOnline(item1->getAvatarId()); + bool online2 = at.isBuddyOnline(item2->getAvatarId()); + + if (online1 == online2) + { + std::string name1 = item1->getAvatarName(); + std::string name2 = item2->getAvatarName(); + + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); + + return name1 < name2; + } + + return online1 > online2; + } }; /** Compares avatar items by distance between you and them */ class LLAvatarItemDistanceComparator : public LLAvatarItemComparator { public: - typedef std::map < LLUUID, LLVector3d > id_to_pos_map_t; - LLAvatarItemDistanceComparator() {}; + typedef std::map < LLUUID, LLVector3d > id_to_pos_map_t; + LLAvatarItemDistanceComparator() {}; - void updateAvatarsPositions(std::vector& positions, uuid_vec_t& uuids) - { - std::vector::const_iterator - pos_it = positions.begin(), - pos_end = positions.end(); + void updateAvatarsPositions(std::vector& positions, uuid_vec_t& uuids) + { + std::vector::const_iterator + pos_it = positions.begin(), + pos_end = positions.end(); - uuid_vec_t::const_iterator - id_it = uuids.begin(), - id_end = uuids.end(); + uuid_vec_t::const_iterator + id_it = uuids.begin(), + id_end = uuids.end(); - LLAvatarItemDistanceComparator::id_to_pos_map_t pos_map; + LLAvatarItemDistanceComparator::id_to_pos_map_t pos_map; - mAvatarsPositions.clear(); + mAvatarsPositions.clear(); - for (;pos_it != pos_end && id_it != id_end; ++pos_it, ++id_it ) - { - mAvatarsPositions[*id_it] = *pos_it; - } - }; + for (;pos_it != pos_end && id_it != id_end; ++pos_it, ++id_it ) + { + mAvatarsPositions[*id_it] = *pos_it; + } + }; protected: - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { - const LLVector3d& me_pos = gAgent.getPositionGlobal(); - const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second; - const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second; - - return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos); - } + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { + const LLVector3d& me_pos = gAgent.getPositionGlobal(); + const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second; + const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second; + + return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos); + } private: - id_to_pos_map_t mAvatarsPositions; + id_to_pos_map_t mAvatarsPositions; }; /** Comparator for comparing nearby avatar items by last spoken time */ class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator { public: - LLAvatarItemRecentSpeakerComparator() {}; - virtual ~LLAvatarItemRecentSpeakerComparator() {}; + LLAvatarItemRecentSpeakerComparator() {}; + virtual ~LLAvatarItemRecentSpeakerComparator() {}; protected: - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { - LLPointer lhs = LLActiveSpeakerMgr::instance().findSpeaker(item1->getAvatarId()); - LLPointer rhs = LLActiveSpeakerMgr::instance().findSpeaker(item2->getAvatarId()); - if ( lhs.notNull() && rhs.notNull() ) - { - // Compare by last speaking time - if( lhs->mLastSpokeTime != rhs->mLastSpokeTime ) - return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime ); - } - else if ( lhs.notNull() ) - { - // True if only item1 speaker info available - return true; - } - else if ( rhs.notNull() ) - { - // False if only item2 speaker info available - return false; - } - // By default compare by name. - return LLAvatarItemNameComparator::doCompare(item1, item2); - } + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { + LLPointer lhs = LLActiveSpeakerMgr::instance().findSpeaker(item1->getAvatarId()); + LLPointer rhs = LLActiveSpeakerMgr::instance().findSpeaker(item2->getAvatarId()); + if ( lhs.notNull() && rhs.notNull() ) + { + // Compare by last speaking time + if( lhs->mLastSpokeTime != rhs->mLastSpokeTime ) + return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime ); + } + else if ( lhs.notNull() ) + { + // True if only item1 speaker info available + return true; + } + else if ( rhs.notNull() ) + { + // False if only item2 speaker info available + return false; + } + // By default compare by name. + return LLAvatarItemNameComparator::doCompare(item1, item2); + } }; class LLAvatarItemRecentArrivalComparator : public LLAvatarItemNameComparator { public: - LLAvatarItemRecentArrivalComparator() {}; - virtual ~LLAvatarItemRecentArrivalComparator() {}; + LLAvatarItemRecentArrivalComparator() {}; + virtual ~LLAvatarItemRecentArrivalComparator() {}; protected: - virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const - { + virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const + { - F32 arr_time1 = LLRecentPeople::instance().getArrivalTimeByID(item1->getAvatarId()); - F32 arr_time2 = LLRecentPeople::instance().getArrivalTimeByID(item2->getAvatarId()); + F32 arr_time1 = LLRecentPeople::instance().getArrivalTimeByID(item1->getAvatarId()); + F32 arr_time2 = LLRecentPeople::instance().getArrivalTimeByID(item2->getAvatarId()); - if (arr_time1 == arr_time2) - { - std::string name1 = item1->getAvatarName(); - std::string name2 = item2->getAvatarName(); + if (arr_time1 == arr_time2) + { + std::string name1 = item1->getAvatarName(); + std::string name2 = item2->getAvatarName(); - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); - return name1 < name2; - } + return name1 < name2; + } - return arr_time1 > arr_time2; - } + return arr_time1 > arr_time2; + } }; static const LLAvatarItemRecentComparator RECENT_COMPARATOR; @@ -248,35 +248,35 @@ static LLPanelInjector t_people("panel_people"); //============================================================================= /** - * Updates given list either on regular basis or on external events (up to implementation). + * Updates given list either on regular basis or on external events (up to implementation). */ class LLPanelPeople::Updater { public: - typedef boost::function callback_t; - Updater(callback_t cb) - : mCallback(cb) - { - } - - virtual ~Updater() - { - } - - /** - * Activate/deactivate updater. - * - * This may start/stop regular updates. - */ - virtual void setActive(bool) {} + typedef boost::function callback_t; + Updater(callback_t cb) + : mCallback(cb) + { + } + + virtual ~Updater() + { + } + + /** + * Activate/deactivate updater. + * + * This may start/stop regular updates. + */ + virtual void setActive(bool) {} protected: - void update() - { - mCallback(); - } + void update() + { + mCallback(); + } - callback_t mCallback; + callback_t mCallback; }; /** @@ -285,233 +285,233 @@ protected: class LLButtonsUpdater : public LLPanelPeople::Updater, public LLFriendObserver { public: - LLButtonsUpdater(callback_t cb) - : LLPanelPeople::Updater(cb) - { - LLAvatarTracker::instance().addObserver(this); - } - - ~LLButtonsUpdater() - { - LLAvatarTracker::instance().removeObserver(this); - } - - /*virtual*/ void changed(U32 mask) - { - (void) mask; - update(); - } + LLButtonsUpdater(callback_t cb) + : LLPanelPeople::Updater(cb) + { + LLAvatarTracker::instance().addObserver(this); + } + + ~LLButtonsUpdater() + { + LLAvatarTracker::instance().removeObserver(this); + } + + /*virtual*/ void changed(U32 mask) + { + (void) mask; + update(); + } }; class LLAvatarListUpdater : public LLPanelPeople::Updater, public LLEventTimer { public: - LLAvatarListUpdater(callback_t cb, F32 period) - : LLEventTimer(period), - LLPanelPeople::Updater(cb) - { - stop(); - } - - bool tick() override // from LLEventTimer - { - return false; - } + LLAvatarListUpdater(callback_t cb, F32 period) + : LLEventTimer(period), + LLPanelPeople::Updater(cb) + { + stop(); + } + + bool tick() override // from LLEventTimer + { + return false; + } }; /** * Updates the friends list. - * - * Updates the list on external events which trigger the changed() method. + * + * Updates the list on external events which trigger the changed() method. */ class LLFriendListUpdater : public LLAvatarListUpdater, public LLFriendObserver { - LOG_CLASS(LLFriendListUpdater); - class LLInventoryFriendCardObserver; - -public: - friend class LLInventoryFriendCardObserver; - LLFriendListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT) - , mIsActive(false) - { - LLAvatarTracker::instance().addObserver(this); - - // For notification when SIP online status changes. - LLVoiceClient::getInstance()->addObserver(this); - mInvObserver = new LLInventoryFriendCardObserver(this); - } - - ~LLFriendListUpdater() - { - // will be deleted by ~LLInventoryModel - //delete mInvObserver; + LOG_CLASS(LLFriendListUpdater); + class LLInventoryFriendCardObserver; + +public: + friend class LLInventoryFriendCardObserver; + LLFriendListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT) + , mIsActive(false) + { + LLAvatarTracker::instance().addObserver(this); + + // For notification when SIP online status changes. + LLVoiceClient::getInstance()->addObserver(this); + mInvObserver = new LLInventoryFriendCardObserver(this); + } + + ~LLFriendListUpdater() + { + // will be deleted by ~LLInventoryModel + //delete mInvObserver; if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->removeObserver(this); } - LLAvatarTracker::instance().removeObserver(this); - } - - void changed(U32 mask) override - { - if (mIsActive) - { - // events can arrive quickly in bulk - we need not process EVERY one of them - - // so we wait a short while to let others pile-in, and process them in aggregate. - start(); - } - - // save-up all the mask-bits which have come-in - mMask |= mask; - } - - - bool tick() override - { - if (!mIsActive) return FALSE; - - if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) - { - update(); - } - - // Stop updates. - stop(); - mMask = 0; - - return false; - } - - void setActive(bool active) override - { - mIsActive = active; - if (active) - { - tick(); - } - } + LLAvatarTracker::instance().removeObserver(this); + } + + void changed(U32 mask) override + { + if (mIsActive) + { + // events can arrive quickly in bulk - we need not process EVERY one of them - + // so we wait a short while to let others pile-in, and process them in aggregate. + start(); + } + + // save-up all the mask-bits which have come-in + mMask |= mask; + } + + + bool tick() override + { + if (!mIsActive) return FALSE; + + if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) + { + update(); + } + + // Stop updates. + stop(); + mMask = 0; + + return false; + } + + void setActive(bool active) override + { + mIsActive = active; + if (active) + { + tick(); + } + } private: - U32 mMask; - LLInventoryFriendCardObserver* mInvObserver; - bool mIsActive; - - /** - * This class is intended for updating Friend List when Inventory Friend Card is added/removed. - * - * The main usage is when Inventory Friends/All content is added while synchronizing with - * friends list on startup is performed. In this case Friend Panel should be updated when - * missing Inventory Friend Card is created. - * *NOTE: updating is fired when Inventory item is added into CallingCards/Friends subfolder. - * Otherwise LLFriendObserver functionality is enough to keep Friends Panel synchronized. - */ - class LLInventoryFriendCardObserver : public LLInventoryObserver - { - LOG_CLASS(LLFriendListUpdater::LLInventoryFriendCardObserver); - - friend class LLFriendListUpdater; - - private: - LLInventoryFriendCardObserver(LLFriendListUpdater* updater) : mUpdater(updater) - { - gInventory.addObserver(this); - } - ~LLInventoryFriendCardObserver() - { - gInventory.removeObserver(this); - } - /*virtual*/ void changed(U32 mask) - { - LL_DEBUGS() << "Inventory changed: " << mask << LL_ENDL; - - static bool synchronize_friends_folders = true; - if (synchronize_friends_folders) - { - // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder, - // fetches their contents if needed and synchronizes it with buddies list. - // If the folders are not found they are created. - LLFriendCardsManager::instance().syncFriendCardsFolders(); - synchronize_friends_folders = false; - } - - // *NOTE: deleting of InventoryItem is performed via moving to Trash. - // That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE - if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED) - { - LL_DEBUGS() << "Calling card added: count: " << gInventory.getChangedIDs().size() - << ", first Inventory ID: "<< (*gInventory.getChangedIDs().begin()) - << LL_ENDL; - - bool friendFound = false; - std::set changedIDs = gInventory.getChangedIDs(); - for (std::set::const_iterator it = changedIDs.begin(); it != changedIDs.end(); ++it) - { - if (isDescendentOfInventoryFriends(*it)) - { - friendFound = true; - break; - } - } - - if (friendFound) - { - LL_DEBUGS() << "friend found, panel should be updated" << LL_ENDL; - mUpdater->changed(LLFriendObserver::ADD); - } - } - } - - bool isDescendentOfInventoryFriends(const LLUUID& invItemID) - { - LLViewerInventoryItem * item = gInventory.getItem(invItemID); - if (NULL == item) - return false; - - return LLFriendCardsManager::instance().isItemInAnyFriendsList(item); - } - LLFriendListUpdater* mUpdater; - - static const U32 CALLINGCARD_ADDED = LLInventoryObserver::ADD | LLInventoryObserver::CALLING_CARD; - }; + U32 mMask; + LLInventoryFriendCardObserver* mInvObserver; + bool mIsActive; + + /** + * This class is intended for updating Friend List when Inventory Friend Card is added/removed. + * + * The main usage is when Inventory Friends/All content is added while synchronizing with + * friends list on startup is performed. In this case Friend Panel should be updated when + * missing Inventory Friend Card is created. + * *NOTE: updating is fired when Inventory item is added into CallingCards/Friends subfolder. + * Otherwise LLFriendObserver functionality is enough to keep Friends Panel synchronized. + */ + class LLInventoryFriendCardObserver : public LLInventoryObserver + { + LOG_CLASS(LLFriendListUpdater::LLInventoryFriendCardObserver); + + friend class LLFriendListUpdater; + + private: + LLInventoryFriendCardObserver(LLFriendListUpdater* updater) : mUpdater(updater) + { + gInventory.addObserver(this); + } + ~LLInventoryFriendCardObserver() + { + gInventory.removeObserver(this); + } + /*virtual*/ void changed(U32 mask) + { + LL_DEBUGS() << "Inventory changed: " << mask << LL_ENDL; + + static bool synchronize_friends_folders = true; + if (synchronize_friends_folders) + { + // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder, + // fetches their contents if needed and synchronizes it with buddies list. + // If the folders are not found they are created. + LLFriendCardsManager::instance().syncFriendCardsFolders(); + synchronize_friends_folders = false; + } + + // *NOTE: deleting of InventoryItem is performed via moving to Trash. + // That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE + if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED) + { + LL_DEBUGS() << "Calling card added: count: " << gInventory.getChangedIDs().size() + << ", first Inventory ID: "<< (*gInventory.getChangedIDs().begin()) + << LL_ENDL; + + bool friendFound = false; + std::set changedIDs = gInventory.getChangedIDs(); + for (std::set::const_iterator it = changedIDs.begin(); it != changedIDs.end(); ++it) + { + if (isDescendentOfInventoryFriends(*it)) + { + friendFound = true; + break; + } + } + + if (friendFound) + { + LL_DEBUGS() << "friend found, panel should be updated" << LL_ENDL; + mUpdater->changed(LLFriendObserver::ADD); + } + } + } + + bool isDescendentOfInventoryFriends(const LLUUID& invItemID) + { + LLViewerInventoryItem * item = gInventory.getItem(invItemID); + if (NULL == item) + return false; + + return LLFriendCardsManager::instance().isItemInAnyFriendsList(item); + } + LLFriendListUpdater* mUpdater; + + static const U32 CALLINGCARD_ADDED = LLInventoryObserver::ADD | LLInventoryObserver::CALLING_CARD; + }; }; /** * Periodically updates the nearby people list while the Nearby tab is active. - * + * * The period is defined by NEARBY_LIST_UPDATE_INTERVAL constant. */ class LLNearbyListUpdater : public LLAvatarListUpdater { - LOG_CLASS(LLNearbyListUpdater); + LOG_CLASS(LLNearbyListUpdater); public: - LLNearbyListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, NEARBY_LIST_UPDATE_INTERVAL) - { - setActive(false); - } - - void setActive(bool val) override - { - if (val) - { - // update immediately and start regular updates - update(); - start(); - } - else - { - // stop regular updates - stop(); - } - } - - bool tick() override - { - update(); - return false; - } + LLNearbyListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, NEARBY_LIST_UPDATE_INTERVAL) + { + setActive(false); + } + + void setActive(bool val) override + { + if (val) + { + // update immediately and start regular updates + update(); + start(); + } + else + { + // stop regular updates + stop(); + } + } + + bool tick() override + { + update(); + return false; + } private: }; @@ -520,83 +520,83 @@ private: */ class LLRecentListUpdater : public LLAvatarListUpdater, public boost::signals2::trackable { - LOG_CLASS(LLRecentListUpdater); + LOG_CLASS(LLRecentListUpdater); public: - LLRecentListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, 0) - { - LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this)); - } + LLRecentListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, 0) + { + LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this)); + } }; //============================================================================= LLPanelPeople::LLPanelPeople() - : LLPanel(), - mTabContainer(NULL), - mOnlineFriendList(NULL), - mAllFriendList(NULL), - mNearbyList(NULL), - mRecentList(NULL), - mGroupList(NULL), - mMiniMap(NULL) + : LLPanel(), + mTabContainer(NULL), + mOnlineFriendList(NULL), + mAllFriendList(NULL), + mNearbyList(NULL), + mRecentList(NULL), + mGroupList(NULL), + mMiniMap(NULL) { - mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); - mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); - mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); - mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this)); - - mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); - mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); - mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Group.Minus", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Chat", boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - mCommitCallbackRegistrar.add("People.Gear", boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1)); - - mCommitCallbackRegistrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2)); - mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); - - mEnableCallbackRegistrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2)); - mEnableCallbackRegistrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2)); - mEnableCallbackRegistrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2)); - - mEnableCallbackRegistrar.add("People.Group.Plus.Validate", boost::bind(&LLPanelPeople::onGroupPlusButtonValidate, this)); - - doPeriodically(boost::bind(&LLPanelPeople::updateNearbyArrivalTime, this), 2.0); + mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); + mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); + mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); + mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this)); + + mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); + mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); + mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); + mCommitCallbackRegistrar.add("People.Group.Minus", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); + mCommitCallbackRegistrar.add("People.Chat", boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + mCommitCallbackRegistrar.add("People.Gear", boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1)); + + mCommitCallbackRegistrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2)); + mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); + + mEnableCallbackRegistrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2)); + mEnableCallbackRegistrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2)); + mEnableCallbackRegistrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2)); + + mEnableCallbackRegistrar.add("People.Group.Plus.Validate", boost::bind(&LLPanelPeople::onGroupPlusButtonValidate, this)); + + doPeriodically(boost::bind(&LLPanelPeople::updateNearbyArrivalTime, this), 2.0); } LLPanelPeople::~LLPanelPeople() { - delete mButtonsUpdater; - delete mNearbyListUpdater; - delete mFriendListUpdater; - delete mRecentListUpdater; - - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + delete mButtonsUpdater; + delete mNearbyListUpdater; + delete mFriendListUpdater; + delete mRecentListUpdater; + + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->removeObserver(this); + } } void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list) { - if(!avatar_list) - { - LL_ERRS() << "Bad parameter" << LL_ENDL; - return; - } - - bool expanded = param.asBoolean(); - - setAccordionCollapsedByUser(ctrl, !expanded); - if(!expanded) - { - avatar_list->resetSelection(); - } + if(!avatar_list) + { + LL_ERRS() << "Bad parameter" << LL_ENDL; + return; + } + + bool expanded = param.asBoolean(); + + setAccordionCollapsedByUser(ctrl, !expanded); + if(!expanded) + { + avatar_list->resetSelection(); + } } @@ -610,574 +610,574 @@ void LLPanelPeople::removePicker() BOOL LLPanelPeople::postBuild() { - S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); - - getChild("nearby_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - getChild("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - getChild("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - getChild("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - - if(LLAgentBenefitsMgr::current().getGroupMembershipLimit() < max_premium) - { - getChild("groupcount")->setText(getString("GroupCountWithInfo")); - getChild("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); - } - - mTabContainer = getChild("tabs"); - mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); - mSavedFilters.resize(mTabContainer->getTabCount()); - mSavedOriginalFilters.resize(mTabContainer->getTabCount()); - - LLPanel* friends_tab = getChild(FRIENDS_TAB_NAME); - // updater is active only if panel is visible to user. - friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2)); + S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); + + getChild("nearby_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + + if(LLAgentBenefitsMgr::current().getGroupMembershipLimit() < max_premium) + { + getChild("groupcount")->setText(getString("GroupCountWithInfo")); + getChild("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); + } + + mTabContainer = getChild("tabs"); + mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); + mSavedFilters.resize(mTabContainer->getTabCount()); + mSavedOriginalFilters.resize(mTabContainer->getTabCount()); + + LLPanel* friends_tab = getChild(FRIENDS_TAB_NAME); + // 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)); - mOnlineFriendList = friends_tab->getChild("avatars_online"); - mAllFriendList = friends_tab->getChild("avatars_all"); - mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); - mOnlineFriendList->setShowIcons("FriendsListShowIcons"); - mOnlineFriendList->showPermissions("FriendsListShowPermissions"); - mOnlineFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); - mAllFriendList->setNoItemsCommentText(getString("no_friends")); - mAllFriendList->setShowIcons("FriendsListShowIcons"); - mAllFriendList->showPermissions("FriendsListShowPermissions"); - mAllFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); - - LLPanel* nearby_tab = getChild(NEARBY_TAB_NAME); - nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2)); - mNearbyList = nearby_tab->getChild("avatar_list"); - mNearbyList->setNoItemsCommentText(getString("no_one_near")); - mNearbyList->setNoItemsMsg(getString("no_one_near")); - mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); - mNearbyList->setShowIcons("NearbyListShowIcons"); - mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames")); - mMiniMap = (LLNetMap*)getChildView("Net Map",true); - mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? - getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); - - mRecentList = getChild(RECENT_TAB_NAME)->getChild("avatar_list"); - mRecentList->setNoItemsCommentText(getString("no_recent_people")); - mRecentList->setNoItemsMsg(getString("no_recent_people")); - mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people")); - mRecentList->setShowIcons("RecentListShowIcons"); - - mGroupList = getChild("group_list"); - mGroupList->setNoItemsCommentText(getString("no_groups_msg")); - mGroupList->setNoItemsMsg(getString("no_groups_msg")); - mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); - - mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyPeopleContextMenu); - mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); - mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); - mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); - - setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); - setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); - setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false); - - mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - - mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); - mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); - mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); - mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); - - // Set openning IM as default on return action for avatar lists - mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); - - mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this)); - mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); - - LLMenuButton* groups_gear_btn = getChild("groups_gear_btn"); - - // Use the context menu of the Groups list for the Groups tab gear menu. - LLToggleableMenu* groups_gear_menu = mGroupList->getContextMenu(); - if (groups_gear_menu) - { - groups_gear_btn->setMenu(groups_gear_menu, LLMenuButton::MP_BOTTOM_LEFT); - } - else - { - LL_WARNS() << "People->Groups list menu not found" << LL_ENDL; - } - - LLAccordionCtrlTab* accordion_tab = getChild("tab_all"); - accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList)); - - accordion_tab = getChild("tab_online"); - accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList)); - - // Must go after setting commit callback and initializing all pointers to children. - mTabContainer->selectTabByName(NEARBY_TAB_NAME); - - LLVoiceClient::getInstance()->addObserver(this); - - // call this method in case some list is empty and buttons can be in inconsistent state - updateButtons(); - - mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); - mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); - - return TRUE; + mOnlineFriendList = friends_tab->getChild("avatars_online"); + mAllFriendList = friends_tab->getChild("avatars_all"); + mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); + mOnlineFriendList->setShowIcons("FriendsListShowIcons"); + mOnlineFriendList->showPermissions("FriendsListShowPermissions"); + mOnlineFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); + mAllFriendList->setNoItemsCommentText(getString("no_friends")); + mAllFriendList->setShowIcons("FriendsListShowIcons"); + mAllFriendList->showPermissions("FriendsListShowPermissions"); + mAllFriendList->setShowCompleteName(!gSavedSettings.getBOOL("FriendsListHideUsernames")); + + LLPanel* nearby_tab = getChild(NEARBY_TAB_NAME); + nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2)); + mNearbyList = nearby_tab->getChild("avatar_list"); + mNearbyList->setNoItemsCommentText(getString("no_one_near")); + mNearbyList->setNoItemsMsg(getString("no_one_near")); + mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); + mNearbyList->setShowIcons("NearbyListShowIcons"); + mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames")); + mMiniMap = (LLNetMap*)getChildView("Net Map",true); + mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? + getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); + + mRecentList = getChild(RECENT_TAB_NAME)->getChild("avatar_list"); + mRecentList->setNoItemsCommentText(getString("no_recent_people")); + mRecentList->setNoItemsMsg(getString("no_recent_people")); + mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people")); + mRecentList->setShowIcons("RecentListShowIcons"); + + mGroupList = getChild("group_list"); + mGroupList->setNoItemsCommentText(getString("no_groups_msg")); + mGroupList->setNoItemsMsg(getString("no_groups_msg")); + mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); + + mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyPeopleContextMenu); + mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + + setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); + setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); + setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false); + + mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + + mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); + mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); + mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); + mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); + + // Set openning IM as default on return action for avatar lists + mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + + mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this)); + mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + + LLMenuButton* groups_gear_btn = getChild("groups_gear_btn"); + + // Use the context menu of the Groups list for the Groups tab gear menu. + LLToggleableMenu* groups_gear_menu = mGroupList->getContextMenu(); + if (groups_gear_menu) + { + groups_gear_btn->setMenu(groups_gear_menu, LLMenuButton::MP_BOTTOM_LEFT); + } + else + { + LL_WARNS() << "People->Groups list menu not found" << LL_ENDL; + } + + LLAccordionCtrlTab* accordion_tab = getChild("tab_all"); + accordion_tab->setDropDownStateChangedCallback( + boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList)); + + accordion_tab = getChild("tab_online"); + accordion_tab->setDropDownStateChangedCallback( + boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList)); + + // Must go after setting commit callback and initializing all pointers to children. + mTabContainer->selectTabByName(NEARBY_TAB_NAME); + + LLVoiceClient::getInstance()->addObserver(this); + + // call this method in case some list is empty and buttons can be in inconsistent state + updateButtons(); + + mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); + mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); + + return TRUE; } // virtual void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal) { - if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) - { - return; - } - - updateButtons(); + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + updateButtons(); } void LLPanelPeople::updateFriendListHelpText() { - // show special help text for just created account to help finding friends. EXT-4836 - static LLTextBox* no_friends_text = getChild("no_friends_help_text"); - - // 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(); - no_friends_text->setVisible(!any_friend_exists); - if (no_friends_text->getVisible()) - { - //update help text for empty lists - const std::string& filter = mSavedOriginalFilters[mTabContainer->getCurrentPanelIndex()]; - - std::string message_name = filter.empty() ? "no_friends_msg" : "no_filtered_friends_msg"; - LLStringUtil::format_map_t args; - args["[SEARCH_TERM]"] = LLURI::escape(filter); - no_friends_text->setText(getString(message_name, args)); - } + // show special help text for just created account to help finding friends. EXT-4836 + static LLTextBox* no_friends_text = getChild("no_friends_help_text"); + + // 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(); + no_friends_text->setVisible(!any_friend_exists); + if (no_friends_text->getVisible()) + { + //update help text for empty lists + const std::string& filter = mSavedOriginalFilters[mTabContainer->getCurrentPanelIndex()]; + + std::string message_name = filter.empty() ? "no_friends_msg" : "no_filtered_friends_msg"; + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter); + no_friends_text->setText(getString(message_name, args)); + } } void LLPanelPeople::updateFriendList() { - if (!mOnlineFriendList || !mAllFriendList) - return; - - // get all buddies we know about - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - LLAvatarTracker::buddy_map_t all_buddies; - av_tracker.copyBuddyList(all_buddies); - - // save them to the online and all friends vectors - uuid_vec_t& online_friendsp = mOnlineFriendList->getIDs(); - uuid_vec_t& all_friendsp = mAllFriendList->getIDs(); - - all_friendsp.clear(); - online_friendsp.clear(); - - uuid_vec_t buddies_uuids; - LLAvatarTracker::buddy_map_t::const_iterator buddies_iter; - - // Fill the avatar list with friends UUIDs - for (buddies_iter = all_buddies.begin(); buddies_iter != all_buddies.end(); ++buddies_iter) - { - buddies_uuids.push_back(buddies_iter->first); - } - - if (buddies_uuids.size() > 0) - { - LL_DEBUGS() << "Friends added to the list: " << buddies_uuids.size() << LL_ENDL; - all_friendsp = buddies_uuids; - } - else - { - LL_DEBUGS() << "No friends found" << LL_ENDL; - } - - LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); - for (; buddy_it != all_buddies.end(); ++buddy_it) - { - LLUUID buddy_id = buddy_it->first; - if (av_tracker.isBuddyOnline(buddy_id)) - online_friendsp.push_back(buddy_id); - } - - /* - * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items. - * But avatarlist can be updated only if it is visible @see LLAvatarList::draw(); - * So we need to do force update of lists to avoid inconsistency of data and view of avatarlist. - */ - mOnlineFriendList->setDirty(true, !mOnlineFriendList->filterHasMatches());// do force update if list do NOT have items - mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches()); - //update trash and other buttons according to a selected item - updateButtons(); - showFriendsAccordionsIfNeeded(); + if (!mOnlineFriendList || !mAllFriendList) + return; + + // get all buddies we know about + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + LLAvatarTracker::buddy_map_t all_buddies; + av_tracker.copyBuddyList(all_buddies); + + // save them to the online and all friends vectors + uuid_vec_t& online_friendsp = mOnlineFriendList->getIDs(); + uuid_vec_t& all_friendsp = mAllFriendList->getIDs(); + + all_friendsp.clear(); + online_friendsp.clear(); + + uuid_vec_t buddies_uuids; + LLAvatarTracker::buddy_map_t::const_iterator buddies_iter; + + // Fill the avatar list with friends UUIDs + for (buddies_iter = all_buddies.begin(); buddies_iter != all_buddies.end(); ++buddies_iter) + { + buddies_uuids.push_back(buddies_iter->first); + } + + if (buddies_uuids.size() > 0) + { + LL_DEBUGS() << "Friends added to the list: " << buddies_uuids.size() << LL_ENDL; + all_friendsp = buddies_uuids; + } + else + { + LL_DEBUGS() << "No friends found" << LL_ENDL; + } + + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + for (; buddy_it != all_buddies.end(); ++buddy_it) + { + LLUUID buddy_id = buddy_it->first; + if (av_tracker.isBuddyOnline(buddy_id)) + online_friendsp.push_back(buddy_id); + } + + /* + * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items. + * But avatarlist can be updated only if it is visible @see LLAvatarList::draw(); + * So we need to do force update of lists to avoid inconsistency of data and view of avatarlist. + */ + mOnlineFriendList->setDirty(true, !mOnlineFriendList->filterHasMatches());// do force update if list do NOT have items + mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches()); + //update trash and other buttons according to a selected item + updateButtons(); + showFriendsAccordionsIfNeeded(); } void LLPanelPeople::updateNearbyList() { - if (!mNearbyList) - return; + if (!mNearbyList) + return; - std::vector positions; + std::vector positions; - LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); - mNearbyList->setDirty(); + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + mNearbyList->setDirty(); - DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); - LLActiveSpeakerMgr::instance().update(TRUE); + DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); + LLActiveSpeakerMgr::instance().update(TRUE); } void LLPanelPeople::updateRecentList() { - if (!mRecentList) - return; + if (!mRecentList) + return; - LLRecentPeople::instance().get(mRecentList->getIDs()); - mRecentList->setDirty(); + LLRecentPeople::instance().get(mRecentList->getIDs()); + mRecentList->setDirty(); } void LLPanelPeople::updateButtons() { - std::string cur_tab = getActiveTabName(); - bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); - bool group_tab_active = (cur_tab == GROUP_TAB_NAME); - //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); - LLUUID selected_id; - - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - bool item_selected = (selected_uuids.size() == 1); - bool multiple_selected = (selected_uuids.size() >= 1); - - if (group_tab_active) - { - if (item_selected) - { - selected_id = mGroupList->getSelectedUUID(); - } - - LLPanel* groups_panel = mTabContainer->getCurrentPanel(); - groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected - - U32 groups_count = gAgent.mGroups.size(); - S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); - U32 groups_remaining = max_groups > groups_count ? max_groups - groups_count : 0; - groups_panel->getChild("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); - groups_panel->getChild("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_remaining)); - } - else - { - bool is_friend = true; - bool is_self = false; - // Check whether selected avatar is our friend. - if (item_selected) - { - selected_id = selected_uuids.front(); - is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; - is_self = gAgent.getID() == selected_id; - } - - LLPanel* cur_panel = mTabContainer->getCurrentPanel(); - if (cur_panel) - { - if (cur_panel->hasChild("add_friend_btn", TRUE)) - cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); - - if (friends_tab_active) - { - cur_panel->getChildView("friends_del_btn")->setEnabled(multiple_selected); - } - - if (!group_tab_active) - { - cur_panel->getChildView("gear_btn")->setEnabled(multiple_selected); - } - } - } + std::string cur_tab = getActiveTabName(); + bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); + bool group_tab_active = (cur_tab == GROUP_TAB_NAME); + //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); + LLUUID selected_id; + + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + bool item_selected = (selected_uuids.size() == 1); + bool multiple_selected = (selected_uuids.size() >= 1); + + if (group_tab_active) + { + if (item_selected) + { + selected_id = mGroupList->getSelectedUUID(); + } + + LLPanel* groups_panel = mTabContainer->getCurrentPanel(); + groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected + + U32 groups_count = gAgent.mGroups.size(); + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); + U32 groups_remaining = max_groups > groups_count ? max_groups - groups_count : 0; + groups_panel->getChild("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); + groups_panel->getChild("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_remaining)); + } + else + { + bool is_friend = true; + bool is_self = false; + // Check whether selected avatar is our friend. + if (item_selected) + { + selected_id = selected_uuids.front(); + is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; + is_self = gAgent.getID() == selected_id; + } + + LLPanel* cur_panel = mTabContainer->getCurrentPanel(); + if (cur_panel) + { + if (cur_panel->hasChild("add_friend_btn", TRUE)) + cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); + + if (friends_tab_active) + { + cur_panel->getChildView("friends_del_btn")->setEnabled(multiple_selected); + } + + if (!group_tab_active) + { + cur_panel->getChildView("gear_btn")->setEnabled(multiple_selected); + } + } + } } std::string LLPanelPeople::getActiveTabName() const { - return mTabContainer->getCurrentPanel()->getName(); + return mTabContainer->getCurrentPanel()->getName(); } LLUUID LLPanelPeople::getCurrentItemID() const { - std::string cur_tab = getActiveTabName(); + std::string cur_tab = getActiveTabName(); - if (cur_tab == FRIENDS_TAB_NAME) // this tab has two lists - { - LLUUID cur_online_friend; + if (cur_tab == FRIENDS_TAB_NAME) // this tab has two lists + { + LLUUID cur_online_friend; - if ((cur_online_friend = mOnlineFriendList->getSelectedUUID()).notNull()) - return cur_online_friend; + if ((cur_online_friend = mOnlineFriendList->getSelectedUUID()).notNull()) + return cur_online_friend; - return mAllFriendList->getSelectedUUID(); - } + return mAllFriendList->getSelectedUUID(); + } - if (cur_tab == NEARBY_TAB_NAME) - return mNearbyList->getSelectedUUID(); + if (cur_tab == NEARBY_TAB_NAME) + return mNearbyList->getSelectedUUID(); - if (cur_tab == RECENT_TAB_NAME) - return mRecentList->getSelectedUUID(); + if (cur_tab == RECENT_TAB_NAME) + return mRecentList->getSelectedUUID(); - if (cur_tab == GROUP_TAB_NAME) - return mGroupList->getSelectedUUID(); + if (cur_tab == GROUP_TAB_NAME) + return mGroupList->getSelectedUUID(); - if (cur_tab == BLOCKED_TAB_NAME) - return LLUUID::null; // FIXME? + if (cur_tab == BLOCKED_TAB_NAME) + return LLUUID::null; // FIXME? - llassert(0 && "unknown tab selected"); - return LLUUID::null; + llassert(0 && "unknown tab selected"); + return LLUUID::null; } void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const { - std::string cur_tab = getActiveTabName(); - - if (cur_tab == FRIENDS_TAB_NAME) - { - // friends tab has two lists - mOnlineFriendList->getSelectedUUIDs(selected_uuids); - mAllFriendList->getSelectedUUIDs(selected_uuids); - } - else if (cur_tab == NEARBY_TAB_NAME) - mNearbyList->getSelectedUUIDs(selected_uuids); - else if (cur_tab == RECENT_TAB_NAME) - mRecentList->getSelectedUUIDs(selected_uuids); - else if (cur_tab == GROUP_TAB_NAME) - mGroupList->getSelectedUUIDs(selected_uuids); - else if (cur_tab == BLOCKED_TAB_NAME) - selected_uuids.clear(); // FIXME? - else - llassert(0 && "unknown tab selected"); + std::string cur_tab = getActiveTabName(); + + if (cur_tab == FRIENDS_TAB_NAME) + { + // friends tab has two lists + mOnlineFriendList->getSelectedUUIDs(selected_uuids); + mAllFriendList->getSelectedUUIDs(selected_uuids); + } + else if (cur_tab == NEARBY_TAB_NAME) + mNearbyList->getSelectedUUIDs(selected_uuids); + else if (cur_tab == RECENT_TAB_NAME) + mRecentList->getSelectedUUIDs(selected_uuids); + else if (cur_tab == GROUP_TAB_NAME) + mGroupList->getSelectedUUIDs(selected_uuids); + else if (cur_tab == BLOCKED_TAB_NAME) + selected_uuids.clear(); // FIXME? + else + llassert(0 && "unknown tab selected"); } void LLPanelPeople::showGroupMenu(LLMenuGL* menu) { - // Shows the menu at the top of the button bar. - - // Calculate its coordinates. - // (assumes that groups panel is the current tab) - LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild("bottom_panel"); - LLPanel* parent_panel = mTabContainer->getCurrentPanel(); - menu->arrangeAndClear(); - S32 menu_height = menu->getRect().getHeight(); - S32 menu_x = -2; // *HACK: compensates HPAD in showPopup() - S32 menu_y = bottom_panel->getRect().mTop + menu_height; - - // Actually show the menu. - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(parent_panel, menu, menu_x, menu_y); + // Shows the menu at the top of the button bar. + + // Calculate its coordinates. + // (assumes that groups panel is the current tab) + LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild("bottom_panel"); + LLPanel* parent_panel = mTabContainer->getCurrentPanel(); + menu->arrangeAndClear(); + S32 menu_height = menu->getRect().getHeight(); + S32 menu_x = -2; // *HACK: compensates HPAD in showPopup() + S32 menu_y = bottom_panel->getRect().mTop + menu_height; + + // Actually show the menu. + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(parent_panel, menu, menu_x, menu_y); } void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save) { - switch (order) - { - case E_SORT_BY_NAME: - list->sortByName(); - break; - case E_SORT_BY_STATUS: - list->setComparator(&STATUS_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_MOST_RECENT: - list->setComparator(&RECENT_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_RECENT_SPEAKERS: - list->setComparator(&RECENT_SPEAKER_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_DISTANCE: - list->setComparator(&DISTANCE_COMPARATOR); - list->sort(); - break; - case E_SORT_BY_RECENT_ARRIVAL: - list->setComparator(&RECENT_ARRIVAL_COMPARATOR); - list->sort(); - break; - default: - LL_WARNS() << "Unrecognized people sort order for " << list->getName() << LL_ENDL; - return; - } - - if (save) - { - std::string setting; - - if (list == mAllFriendList || list == mOnlineFriendList) - setting = "FriendsSortOrder"; - else if (list == mRecentList) - setting = "RecentPeopleSortOrder"; - else if (list == mNearbyList) - setting = "NearbyPeopleSortOrder"; - - if (!setting.empty()) - gSavedSettings.setU32(setting, order); - } + switch (order) + { + case E_SORT_BY_NAME: + list->sortByName(); + break; + case E_SORT_BY_STATUS: + list->setComparator(&STATUS_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_MOST_RECENT: + list->setComparator(&RECENT_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_RECENT_SPEAKERS: + list->setComparator(&RECENT_SPEAKER_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_DISTANCE: + list->setComparator(&DISTANCE_COMPARATOR); + list->sort(); + break; + case E_SORT_BY_RECENT_ARRIVAL: + list->setComparator(&RECENT_ARRIVAL_COMPARATOR); + list->sort(); + break; + default: + LL_WARNS() << "Unrecognized people sort order for " << list->getName() << LL_ENDL; + return; + } + + if (save) + { + std::string setting; + + if (list == mAllFriendList || list == mOnlineFriendList) + setting = "FriendsSortOrder"; + else if (list == mRecentList) + setting = "RecentPeopleSortOrder"; + else if (list == mNearbyList) + setting = "NearbyPeopleSortOrder"; + + if (!setting.empty()) + gSavedSettings.setU32(setting, order); + } } void LLPanelPeople::onFilterEdit(const std::string& search_string) { - const S32 cur_tab_idx = mTabContainer->getCurrentPanelIndex(); - std::string& filter = mSavedOriginalFilters[cur_tab_idx]; - std::string& saved_filter = mSavedFilters[cur_tab_idx]; - - filter = search_string; - LLStringUtil::trimHead(filter); - - // Searches are case-insensitive - std::string search_upper = filter; - LLStringUtil::toUpper(search_upper); - - if (saved_filter == search_upper) - return; - - saved_filter = search_upper; - - // Apply new filter to the current tab. - const std::string cur_tab = getActiveTabName(); - if (cur_tab == NEARBY_TAB_NAME) - { - mNearbyList->setNameFilter(filter); - } - else if (cur_tab == FRIENDS_TAB_NAME) - { - // store accordion tabs opened/closed state before any manipulation with accordion tabs - if (!saved_filter.empty()) + const S32 cur_tab_idx = mTabContainer->getCurrentPanelIndex(); + std::string& filter = mSavedOriginalFilters[cur_tab_idx]; + std::string& saved_filter = mSavedFilters[cur_tab_idx]; + + filter = search_string; + LLStringUtil::trimHead(filter); + + // Searches are case-insensitive + std::string search_upper = filter; + LLStringUtil::toUpper(search_upper); + + if (saved_filter == search_upper) + return; + + saved_filter = search_upper; + + // Apply new filter to the current tab. + const std::string cur_tab = getActiveTabName(); + if (cur_tab == NEARBY_TAB_NAME) + { + mNearbyList->setNameFilter(filter); + } + else if (cur_tab == FRIENDS_TAB_NAME) + { + // store accordion tabs opened/closed state before any manipulation with accordion tabs + if (!saved_filter.empty()) { notifyChildren(LLSD().with("action","store_state")); } - mOnlineFriendList->setNameFilter(filter); - mAllFriendList->setNameFilter(filter); + mOnlineFriendList->setNameFilter(filter); + mAllFriendList->setNameFilter(filter); setAccordionCollapsedByUser("tab_online", false); setAccordionCollapsedByUser("tab_all", false); showFriendsAccordionsIfNeeded(); - // restore accordion tabs state _after_ all manipulations - if(saved_filter.empty()) + // restore accordion tabs state _after_ all manipulations + if(saved_filter.empty()) { notifyChildren(LLSD().with("action","restore_state")); } } - else if (cur_tab == GROUP_TAB_NAME) - { - mGroupList->setNameFilter(filter); - } - else if (cur_tab == RECENT_TAB_NAME) - { - mRecentList->setNameFilter(filter); - } + else if (cur_tab == GROUP_TAB_NAME) + { + mGroupList->setNameFilter(filter); + } + else if (cur_tab == RECENT_TAB_NAME) + { + mRecentList->setNameFilter(filter); + } } void LLPanelPeople::onGroupLimitInfo() { - LLSD args; - - S32 max_basic = LLAgentBenefitsMgr::get("Base").getGroupMembershipLimit(); - S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); - - args["MAX_BASIC"] = max_basic; - args["MAX_PREMIUM"] = max_premium; - - if (LLAgentBenefitsMgr::has("Premium_Plus")) - { - S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium_Plus").getGroupMembershipLimit(); - args["MAX_PREMIUM_PLUS"] = max_premium_plus; - LLNotificationsUtil::add("GroupLimitInfoPlus", args); - } - else - { - LLNotificationsUtil::add("GroupLimitInfo", args); - } + LLSD args; + + S32 max_basic = LLAgentBenefitsMgr::get("Base").getGroupMembershipLimit(); + S32 max_premium = LLAgentBenefitsMgr::get("Premium").getGroupMembershipLimit(); + + args["MAX_BASIC"] = max_basic; + args["MAX_PREMIUM"] = max_premium; + + if (LLAgentBenefitsMgr::has("Premium_Plus")) + { + S32 max_premium_plus = LLAgentBenefitsMgr::get("Premium_Plus").getGroupMembershipLimit(); + args["MAX_PREMIUM_PLUS"] = max_premium_plus; + LLNotificationsUtil::add("GroupLimitInfoPlus", args); + } + else + { + LLNotificationsUtil::add("GroupLimitInfo", args); + } } void LLPanelPeople::onTabSelected(const LLSD& param) { - std::string tab_name = getChild(param.asString())->getName(); - updateButtons(); + std::string tab_name = getChild(param.asString())->getName(); + updateButtons(); - showFriendsAccordionsIfNeeded(); + showFriendsAccordionsIfNeeded(); } void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) { - LLAvatarListItem* item = dynamic_cast(ctrl); - if(!item) - { - return; - } - - LLUUID clicked_id = item->getAvatarId(); - if(gAgent.getID() == clicked_id) - { - return; - } - + LLAvatarListItem* item = dynamic_cast(ctrl); + if(!item) + { + return; + } + + LLUUID clicked_id = item->getAvatarId(); + if(gAgent.getID() == clicked_id) + { + return; + } + #if 0 // SJB: Useful for testing, but not currently functional or to spec - LLAvatarActions::showProfile(clicked_id); + LLAvatarActions::showProfile(clicked_id); #else // spec says open IM window - LLAvatarActions::startIM(clicked_id); + LLAvatarActions::startIM(clicked_id); #endif } void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) { - if (getActiveTabName() == NEARBY_TAB_NAME) - { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - mMiniMap->setSelected(selected_uuids); - } else - // Make sure only one of the friends lists (online/all) has selection. - if (getActiveTabName() == FRIENDS_TAB_NAME) - { - if (list == mOnlineFriendList) - mAllFriendList->resetSelection(true); - else if (list == mAllFriendList) - mOnlineFriendList->resetSelection(true); - else - llassert(0 && "commit on unknown friends list"); - } - - updateButtons(); + if (getActiveTabName() == NEARBY_TAB_NAME) + { + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + mMiniMap->setSelected(selected_uuids); + } else + // Make sure only one of the friends lists (online/all) has selection. + if (getActiveTabName() == FRIENDS_TAB_NAME) + { + if (list == mOnlineFriendList) + mAllFriendList->resetSelection(true); + else if (list == mAllFriendList) + mOnlineFriendList->resetSelection(true); + else + llassert(0 && "commit on unknown friends list"); + } + + updateButtons(); } void LLPanelPeople::onAddFriendButtonClicked() { - LLUUID id = getCurrentItemID(); - if (id.notNull()) - { - LLAvatarActions::requestFriendshipDialog(id); - } + LLUUID id = getCurrentItemID(); + if (id.notNull()) + { + LLAvatarActions::requestFriendshipDialog(id); + } } bool LLPanelPeople::isItemsFreeOfFriends(const uuid_vec_t& uuids) { - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - for ( uuid_vec_t::const_iterator - id = uuids.begin(), - id_end = uuids.end(); - id != id_end; ++id ) - { - if (av_tracker.isBuddy (*id)) - { - return false; - } - } - return true; + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + for ( uuid_vec_t::const_iterator + id = uuids.begin(), + id_end = uuids.end(); + id != id_end; ++id ) + { + if (av_tracker.isBuddy (*id)) + { + return false; + } + } + return true; } void LLPanelPeople::onAddFriendWizButtonClicked() @@ -1185,397 +1185,397 @@ void LLPanelPeople::onAddFriendWizButtonClicked() LLPanel* cur_panel = mTabContainer->getCurrentPanel(); LLView * button = cur_panel->findChild("friends_add_btn", TRUE); - // Show add friend wizard. + // Show add friend wizard. LLFloater* root_floater = gFloaterView->getParentFloater(this); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelPeople::onAvatarPicked, _1, _2), FALSE, TRUE, FALSE, root_floater->getName(), button); - if (!picker) - { - return; - } - - // Need to disable 'ok' button when friend occurs in selection - picker->setOkBtnEnableCb(boost::bind(&LLPanelPeople::isItemsFreeOfFriends, this, _1)); - - if (root_floater) - { - root_floater->addDependentFloater(picker); - } + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelPeople::onAvatarPicked, _1, _2), FALSE, TRUE, FALSE, root_floater->getName(), button); + if (!picker) + { + return; + } + + // Need to disable 'ok' button when friend occurs in selection + picker->setOkBtnEnableCb(boost::bind(&LLPanelPeople::isItemsFreeOfFriends, this, _1)); + + if (root_floater) + { + root_floater->addDependentFloater(picker); + } mPicker = picker->getHandle(); } void LLPanelPeople::onDeleteFriendButtonClicked() { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - - if (selected_uuids.size() == 1) - { - LLAvatarActions::removeFriendDialog( selected_uuids.front() ); - } - else if (selected_uuids.size() > 1) - { - LLAvatarActions::removeFriendsDialog( selected_uuids ); - } + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + + if (selected_uuids.size() == 1) + { + LLAvatarActions::removeFriendDialog( selected_uuids.front() ); + } + else if (selected_uuids.size() > 1) + { + LLAvatarActions::removeFriendsDialog( selected_uuids ); + } } void LLPanelPeople::onChatButtonClicked() { - LLUUID group_id = getCurrentItemID(); - if (group_id.notNull()) - LLGroupActions::startIM(group_id); + LLUUID group_id = getCurrentItemID(); + if (group_id.notNull()) + LLGroupActions::startIM(group_id); } void LLPanelPeople::onGearButtonClicked(LLUICtrl* btn) { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - // Spawn at bottom left corner of the button. - if (getActiveTabName() == NEARBY_TAB_NAME) - LLPanelPeopleMenus::gNearbyPeopleContextMenu.show(btn, selected_uuids, 0, 0); - else - LLPanelPeopleMenus::gPeopleContextMenu.show(btn, selected_uuids, 0, 0); + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + // Spawn at bottom left corner of the button. + if (getActiveTabName() == NEARBY_TAB_NAME) + LLPanelPeopleMenus::gNearbyPeopleContextMenu.show(btn, selected_uuids, 0, 0); + else + LLPanelPeopleMenus::gPeopleContextMenu.show(btn, selected_uuids, 0, 0); } void LLPanelPeople::onImButtonClicked() { - uuid_vec_t selected_uuids; - getCurrentItemIDs(selected_uuids); - if ( selected_uuids.size() == 1 ) - { - // if selected only one person then start up IM - LLAvatarActions::startIM(selected_uuids.at(0)); - } - else if ( selected_uuids.size() > 1 ) - { - // for multiple selection start up friends conference - LLAvatarActions::startConference(selected_uuids); - } + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + if ( selected_uuids.size() == 1 ) + { + // if selected only one person then start up IM + LLAvatarActions::startIM(selected_uuids.at(0)); + } + else if ( selected_uuids.size() > 1 ) + { + // for multiple selection start up friends conference + LLAvatarActions::startConference(selected_uuids); + } } // static void LLPanelPeople::onAvatarPicked(const uuid_vec_t& ids, const std::vector names) { - if (!names.empty() && !ids.empty()) - LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName()); + if (!names.empty() && !ids.empty()) + LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName()); } bool LLPanelPeople::onGroupPlusButtonValidate() { - if (!gAgent.canJoinGroups()) - { - LLNotificationsUtil::add("JoinedTooManyGroups"); - return false; - } + if (!gAgent.canJoinGroups()) + { + LLNotificationsUtil::add("JoinedTooManyGroups"); + return false; + } - return true; + return true; } void LLPanelPeople::onGroupMinusButtonClicked() { - LLUUID group_id = getCurrentItemID(); - if (group_id.notNull()) - LLGroupActions::leave(group_id); + LLUUID group_id = getCurrentItemID(); + if (group_id.notNull()) + LLGroupActions::leave(group_id); } void LLPanelPeople::onGroupPlusMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); + std::string chosen_item = userdata.asString(); - if (chosen_item == "join_group") - LLGroupActions::search(); - else if (chosen_item == "new_group") - LLGroupActions::createGroup(); + if (chosen_item == "join_group") + LLGroupActions::search(); + else if (chosen_item == "new_group") + LLGroupActions::createGroup(); } void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); - - if (chosen_item == "sort_name") - { - setSortOrder(mAllFriendList, E_SORT_BY_NAME); - } - else if (chosen_item == "sort_status") - { - setSortOrder(mAllFriendList, E_SORT_BY_STATUS); - } - else if (chosen_item == "view_icons") - { - mAllFriendList->toggleIcons(); - mOnlineFriendList->toggleIcons(); - } - else if (chosen_item == "view_permissions") - { - bool show_permissions = !gSavedSettings.getBOOL("FriendsListShowPermissions"); - gSavedSettings.setBOOL("FriendsListShowPermissions", show_permissions); - - mAllFriendList->showPermissions(show_permissions); - mOnlineFriendList->showPermissions(show_permissions); - } - else if (chosen_item == "view_usernames") - { - bool hide_usernames = !gSavedSettings.getBOOL("FriendsListHideUsernames"); - gSavedSettings.setBOOL("FriendsListHideUsernames", hide_usernames); - - mAllFriendList->setShowCompleteName(!hide_usernames); - mAllFriendList->handleDisplayNamesOptionChanged(); - mOnlineFriendList->setShowCompleteName(!hide_usernames); - mOnlineFriendList->handleDisplayNamesOptionChanged(); - } - } + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_name") + { + setSortOrder(mAllFriendList, E_SORT_BY_NAME); + } + else if (chosen_item == "sort_status") + { + setSortOrder(mAllFriendList, E_SORT_BY_STATUS); + } + else if (chosen_item == "view_icons") + { + mAllFriendList->toggleIcons(); + mOnlineFriendList->toggleIcons(); + } + else if (chosen_item == "view_permissions") + { + bool show_permissions = !gSavedSettings.getBOOL("FriendsListShowPermissions"); + gSavedSettings.setBOOL("FriendsListShowPermissions", show_permissions); + + mAllFriendList->showPermissions(show_permissions); + mOnlineFriendList->showPermissions(show_permissions); + } + else if (chosen_item == "view_usernames") + { + bool hide_usernames = !gSavedSettings.getBOOL("FriendsListHideUsernames"); + gSavedSettings.setBOOL("FriendsListHideUsernames", hide_usernames); + + mAllFriendList->setShowCompleteName(!hide_usernames); + mAllFriendList->handleDisplayNamesOptionChanged(); + mOnlineFriendList->setShowCompleteName(!hide_usernames); + mOnlineFriendList->handleDisplayNamesOptionChanged(); + } + } void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); + std::string chosen_item = userdata.asString(); - if (chosen_item == "show_icons") - { - mGroupList->toggleIcons(); - } + if (chosen_item == "show_icons") + { + mGroupList->toggleIcons(); + } } void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); - - if (chosen_item == "sort_by_recent_speakers") - { - setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS); - } - else if (chosen_item == "sort_name") - { - setSortOrder(mNearbyList, E_SORT_BY_NAME); - } - else if (chosen_item == "view_icons") - { - mNearbyList->toggleIcons(); - } - else if (chosen_item == "sort_distance") - { - setSortOrder(mNearbyList, E_SORT_BY_DISTANCE); - } - else if (chosen_item == "sort_arrival") - { - setSortOrder(mNearbyList, E_SORT_BY_RECENT_ARRIVAL); - } - else if (chosen_item == "view_usernames") - { - bool hide_usernames = !gSavedSettings.getBOOL("NearbyListHideUsernames"); - gSavedSettings.setBOOL("NearbyListHideUsernames", hide_usernames); - - mNearbyList->setShowCompleteName(!hide_usernames); - mNearbyList->handleDisplayNamesOptionChanged(); - } + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_by_recent_speakers") + { + setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS); + } + else if (chosen_item == "sort_name") + { + setSortOrder(mNearbyList, E_SORT_BY_NAME); + } + else if (chosen_item == "view_icons") + { + mNearbyList->toggleIcons(); + } + else if (chosen_item == "sort_distance") + { + setSortOrder(mNearbyList, E_SORT_BY_DISTANCE); + } + else if (chosen_item == "sort_arrival") + { + setSortOrder(mNearbyList, E_SORT_BY_RECENT_ARRIVAL); + } + else if (chosen_item == "view_usernames") + { + bool hide_usernames = !gSavedSettings.getBOOL("NearbyListHideUsernames"); + gSavedSettings.setBOOL("NearbyListHideUsernames", hide_usernames); + + mNearbyList->setShowCompleteName(!hide_usernames); + mNearbyList->handleDisplayNamesOptionChanged(); + } } bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata) { - std::string item = userdata.asString(); - U32 sort_order = gSavedSettings.getU32("NearbyPeopleSortOrder"); - - if (item == "sort_by_recent_speakers") - return sort_order == E_SORT_BY_RECENT_SPEAKERS; - if (item == "sort_name") - return sort_order == E_SORT_BY_NAME; - if (item == "sort_distance") - return sort_order == E_SORT_BY_DISTANCE; - if (item == "sort_arrival") - return sort_order == E_SORT_BY_RECENT_ARRIVAL; - - return false; + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("NearbyPeopleSortOrder"); + + if (item == "sort_by_recent_speakers") + return sort_order == E_SORT_BY_RECENT_SPEAKERS; + if (item == "sort_name") + return sort_order == E_SORT_BY_NAME; + if (item == "sort_distance") + return sort_order == E_SORT_BY_DISTANCE; + if (item == "sort_arrival") + return sort_order == E_SORT_BY_RECENT_ARRIVAL; + + return false; } void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata) { - std::string chosen_item = userdata.asString(); - - if (chosen_item == "sort_recent") - { - setSortOrder(mRecentList, E_SORT_BY_MOST_RECENT); - } - else if (chosen_item == "sort_name") - { - setSortOrder(mRecentList, E_SORT_BY_NAME); - } - else if (chosen_item == "view_icons") - { - mRecentList->toggleIcons(); - } + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_recent") + { + setSortOrder(mRecentList, E_SORT_BY_MOST_RECENT); + } + else if (chosen_item == "sort_name") + { + setSortOrder(mRecentList, E_SORT_BY_NAME); + } + else if (chosen_item == "view_icons") + { + mRecentList->toggleIcons(); + } } -bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata) +bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata) { - std::string item = userdata.asString(); - U32 sort_order = gSavedSettings.getU32("FriendsSortOrder"); + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("FriendsSortOrder"); - if (item == "sort_name") - return sort_order == E_SORT_BY_NAME; - if (item == "sort_status") - return sort_order == E_SORT_BY_STATUS; + if (item == "sort_name") + return sort_order == E_SORT_BY_NAME; + if (item == "sort_status") + return sort_order == E_SORT_BY_STATUS; - return false; + return false; } -bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata) +bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata) { - std::string item = userdata.asString(); - U32 sort_order = gSavedSettings.getU32("RecentPeopleSortOrder"); + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("RecentPeopleSortOrder"); - if (item == "sort_recent") - return sort_order == E_SORT_BY_MOST_RECENT; - if (item == "sort_name") - return sort_order == E_SORT_BY_NAME; + if (item == "sort_recent") + return sort_order == E_SORT_BY_MOST_RECENT; + if (item == "sort_name") + return sort_order == E_SORT_BY_NAME; - return false; + return false; } void LLPanelPeople::onMoreButtonClicked() { - // *TODO: not implemented yet + // *TODO: not implemented yet } -void LLPanelPeople::onOpen(const LLSD& key) +void LLPanelPeople::onOpen(const LLSD& key) { - std::string tab_name = key["people_panel_tab_name"]; - if (!tab_name.empty()) - { - mTabContainer->selectTabByName(tab_name); - if(tab_name == BLOCKED_TAB_NAME) - { - LLPanel* blocked_tab = mTabContainer->getCurrentPanel()->findChild("panel_block_list_sidetray"); - if(blocked_tab) - { - blocked_tab->onOpen(key); - } - } - } + std::string tab_name = key["people_panel_tab_name"]; + if (!tab_name.empty()) + { + mTabContainer->selectTabByName(tab_name); + if(tab_name == BLOCKED_TAB_NAME) + { + LLPanel* blocked_tab = mTabContainer->getCurrentPanel()->findChild("panel_block_list_sidetray"); + if(blocked_tab) + { + blocked_tab->onOpen(key); + } + } + } } bool LLPanelPeople::notifyChildren(const LLSD& info) { - if (info.has("task-panel-action") && info["task-panel-action"].asString() == "handle-tri-state") - { - LLSideTrayPanelContainer* container = dynamic_cast(getParent()); - if (!container) - { - LL_WARNS() << "Cannot find People panel container" << LL_ENDL; - return true; - } - - if (container->getCurrentPanelIndex() > 0) - { - // if not on the default panel, switch to it - container->onOpen(LLSD().with(LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME, getName())); - } - else - LLFloaterReg::hideInstance("people"); - - return true; // this notification is only supposed to be handled by task panels - } - - return LLPanel::notifyChildren(info); + if (info.has("task-panel-action") && info["task-panel-action"].asString() == "handle-tri-state") + { + LLSideTrayPanelContainer* container = dynamic_cast(getParent()); + if (!container) + { + LL_WARNS() << "Cannot find People panel container" << LL_ENDL; + return true; + } + + if (container->getCurrentPanelIndex() > 0) + { + // if not on the default panel, switch to it + container->onOpen(LLSD().with(LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME, getName())); + } + else + LLFloaterReg::hideInstance("people"); + + return true; // this notification is only supposed to be handled by task panels + } + + return LLPanel::notifyChildren(info); } void LLPanelPeople::showAccordion(const std::string name, bool show) { - if(name.empty()) - { - LL_WARNS() << "No name provided" << LL_ENDL; - return; - } - - LLAccordionCtrlTab* tab = getChild(name); - tab->setVisible(show); - if(show) - { - // don't expand accordion if it was collapsed by user - if(!isAccordionCollapsedByUser(tab)) - { - // expand accordion - tab->changeOpenClose(false); - } - } + if(name.empty()) + { + LL_WARNS() << "No name provided" << LL_ENDL; + return; + } + + LLAccordionCtrlTab* tab = getChild(name); + tab->setVisible(show); + if(show) + { + // don't expand accordion if it was collapsed by user + if(!isAccordionCollapsedByUser(tab)) + { + // expand accordion + tab->changeOpenClose(false); + } + } } void LLPanelPeople::showFriendsAccordionsIfNeeded() { - if(FRIENDS_TAB_NAME == getActiveTabName()) - { - // Expand and show accordions if needed, else - hide them - showAccordion("tab_online", mOnlineFriendList->filterHasMatches()); - showAccordion("tab_all", mAllFriendList->filterHasMatches()); - - // Rearrange accordions - LLAccordionCtrl* accordion = getChild("friends_accordion"); - accordion->arrange(); - - // *TODO: new no_matched_tabs_text attribute was implemented in accordion (EXT-7368). - // this code should be refactored to use it - // keep help text in a synchronization with accordions visibility. - updateFriendListHelpText(); - } + if(FRIENDS_TAB_NAME == getActiveTabName()) + { + // Expand and show accordions if needed, else - hide them + showAccordion("tab_online", mOnlineFriendList->filterHasMatches()); + showAccordion("tab_all", mAllFriendList->filterHasMatches()); + + // Rearrange accordions + LLAccordionCtrl* accordion = getChild("friends_accordion"); + accordion->arrange(); + + // *TODO: new no_matched_tabs_text attribute was implemented in accordion (EXT-7368). + // this code should be refactored to use it + // keep help text in a synchronization with accordions visibility. + updateFriendListHelpText(); + } } void LLPanelPeople::onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param) { - if(ctrl == mOnlineFriendList) - { - showAccordion("tab_online", param.asInteger()); - } - else if(ctrl == mAllFriendList) - { - showAccordion("tab_all", param.asInteger()); - } + if(ctrl == mOnlineFriendList) + { + showAccordion("tab_online", param.asInteger()); + } + else if(ctrl == mAllFriendList) + { + showAccordion("tab_all", param.asInteger()); + } } void LLPanelPeople::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed) { - if(!acc_tab) - { - LL_WARNS() << "Invalid parameter" << LL_ENDL; - return; - } - - LLSD param = acc_tab->getValue(); - param[COLLAPSED_BY_USER] = collapsed; - acc_tab->setValue(param); + if(!acc_tab) + { + LL_WARNS() << "Invalid parameter" << LL_ENDL; + return; + } + + LLSD param = acc_tab->getValue(); + param[COLLAPSED_BY_USER] = collapsed; + acc_tab->setValue(param); } void LLPanelPeople::setAccordionCollapsedByUser(const std::string& name, bool collapsed) { - setAccordionCollapsedByUser(getChild(name), collapsed); + setAccordionCollapsedByUser(getChild(name), collapsed); } bool LLPanelPeople::isAccordionCollapsedByUser(LLUICtrl* acc_tab) { - if(!acc_tab) - { - LL_WARNS() << "Invalid parameter" << LL_ENDL; - return false; - } - - LLSD param = acc_tab->getValue(); - if(!param.has(COLLAPSED_BY_USER)) - { - return false; - } - return param[COLLAPSED_BY_USER].asBoolean(); + if(!acc_tab) + { + LL_WARNS() << "Invalid parameter" << LL_ENDL; + return false; + } + + LLSD param = acc_tab->getValue(); + if(!param.has(COLLAPSED_BY_USER)) + { + return false; + } + return param[COLLAPSED_BY_USER].asBoolean(); } bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name) { - return isAccordionCollapsedByUser(getChild(name)); + return isAccordionCollapsedByUser(getChild(name)); } bool LLPanelPeople::updateNearbyArrivalTime() { - std::vector positions; - std::vector uuids; - static LLCachedControl range(gSavedSettings, "NearMeRange"); - LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), range); - LLRecentPeople::instance().updateAvatarsArrivalTime(uuids); - return LLApp::isExiting(); + std::vector positions; + std::vector uuids; + static LLCachedControl range(gSavedSettings, "NearMeRange"); + LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), range); + LLRecentPeople::instance().updateAvatarsArrivalTime(uuids); + return LLApp::isExiting(); } diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index a6d628e1ad..449654da6a 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsetkeybinddialog.cpp * @brief LLSetKeyBindDialog class implementation. * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2019, 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$ */ @@ -76,9 +76,9 @@ LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) mContextConeOutAlpha(0.f), mContextConeFadeTime(0.f) { - mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); - mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); - mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } LLSetKeyBindDialog::~LLSetKeyBindDialog() diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 2bc8d04a8e..6799104f9a 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llspeakers.cpp * @brief Management interface for muting and controlling volume of residents currently speaking * * $LicenseInfo:firstyear=2005&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$ */ @@ -46,48 +46,48 @@ extern LLControlGroup gSavedSettings; const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); -LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) : - mStatus(LLSpeaker::STATUS_TEXT_ONLY), - mLastSpokeTime(0.f), - mSpeechVolume(0.f), - mHasSpoken(FALSE), - mHasLeftCurrentCall(FALSE), - mDotColor(LLColor4::white), - mID(id), - mTyping(FALSE), - mSortIndex(0), - mType(type), - mIsModerator(FALSE), - mModeratorMutedVoice(FALSE), - mModeratorMutedText(FALSE) +LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) : + mStatus(LLSpeaker::STATUS_TEXT_ONLY), + mLastSpokeTime(0.f), + mSpeechVolume(0.f), + mHasSpoken(FALSE), + mHasLeftCurrentCall(FALSE), + mDotColor(LLColor4::white), + mID(id), + mTyping(FALSE), + mSortIndex(0), + mType(type), + mIsModerator(FALSE), + mModeratorMutedVoice(FALSE), + mModeratorMutedText(FALSE) { - if (name.empty() && type == SPEAKER_AGENT) - { - lookupName(); - } - else - { - mDisplayName = name; - } + if (name.empty() && type == SPEAKER_AGENT) + { + lookupName(); + } + else + { + mDisplayName = name; + } } void LLSpeaker::lookupName() { - if (mDisplayName.empty()) - { - LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _1, _2)); // todo: can be group??? - } + if (mDisplayName.empty()) + { + LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _1, _2)); // todo: can be group??? + } } void LLSpeaker::onNameCache(const LLUUID& id, const LLAvatarName& av_name) { - mDisplayName = av_name.getUserName(); + mDisplayName = av_name.getUserName(); } bool LLSpeaker::isInVoiceChannel() { - return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED; + return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED; } LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source) @@ -98,9 +98,9 @@ LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source) LLSD LLSpeakerUpdateSpeakerEvent::getValue() { - LLSD ret; - ret["id"] = mSpeakerID; - return ret; + LLSD ret; + ret["id"] = mSpeakerID; + return ret; } LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source) @@ -112,10 +112,10 @@ LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source) LLSD LLSpeakerUpdateModeratorEvent::getValue() { - LLSD ret; - ret["id"] = mSpeakerID; - ret["is_moderator"] = mIsModerator; - return ret; + LLSD ret; + ret["id"] = mSpeakerID; + ret["is_moderator"] = mIsModerator; + return ret; } LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) @@ -125,7 +125,7 @@ LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) LLSD LLSpeakerTextModerationEvent::getValue() { - return std::string("text"); + return std::string("text"); } @@ -136,7 +136,7 @@ LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source) LLSD LLSpeakerVoiceModerationEvent::getValue() { - return std::string("voice"); + return std::string("voice"); } LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id) @@ -147,31 +147,31 @@ LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const L LLSD LLSpeakerListChangeEvent::getValue() { - return mSpeakerID; + return mSpeakerID; } // helper sort class struct LLSortRecentSpeakers { - bool operator()(const LLPointer lhs, const LLPointer rhs) const; + bool operator()(const LLPointer lhs, const LLPointer rhs) const; }; bool LLSortRecentSpeakers::operator()(const LLPointer lhs, const LLPointer rhs) const { - // Sort first on status - if (lhs->mStatus != rhs->mStatus) - { - return (lhs->mStatus < rhs->mStatus); - } - - // and then on last speaking time - if(lhs->mLastSpokeTime != rhs->mLastSpokeTime) - { - return (lhs->mLastSpokeTime > rhs->mLastSpokeTime); - } - - // and finally (only if those are both equal), on name. - return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); + // Sort first on status + if (lhs->mStatus != rhs->mStatus) + { + return (lhs->mStatus < rhs->mStatus); + } + + // and then on last speaking time + if(lhs->mLastSpokeTime != rhs->mLastSpokeTime) + { + return (lhs->mLastSpokeTime > rhs->mLastSpokeTime); + } + + // and finally (only if those are both equal), on name. + return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); } LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id) @@ -183,16 +183,16 @@ LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 acti bool LLSpeakerActionTimer::tick() { - if (mActionCallback) - { - return (BOOL)mActionCallback(mSpeakerId); - } - return true; + if (mActionCallback) + { + return (BOOL)mActionCallback(mSpeakerId); + } + return true; } void LLSpeakerActionTimer::unset() { - mActionCallback = 0; + mActionCallback = 0; } LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay) @@ -203,454 +203,454 @@ LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTime LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage() { - removeAllTimers(); + removeAllTimers(); } void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) { - bool not_found = true; - if (mActionTimersMap.size() > 0) - { - not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); - } - - // If there is already a started timer for the passed UUID don't do anything. - if (not_found) - { - // Starting a timer to remove an participant after delay is completed - mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id, - new LLSpeakerActionTimer( - boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1), - mActionDelay, speaker_id))); - } + bool not_found = true; + if (mActionTimersMap.size() > 0) + { + not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); + } + + // If there is already a started timer for the passed UUID don't do anything. + if (not_found) + { + // Starting a timer to remove an participant after delay is completed + mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id, + new LLSpeakerActionTimer( + boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1), + mActionDelay, speaker_id))); + } } void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id) { - if (mActionTimersMap.size() == 0) return; + if (mActionTimersMap.size() == 0) return; - LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); + LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); - if (it_speaker != mActionTimersMap.end()) - { - it_speaker->second->unset(); - mActionTimersMap.erase(it_speaker); - } + if (it_speaker != mActionTimersMap.end()) + { + it_speaker->second->unset(); + mActionTimersMap.erase(it_speaker); + } } void LLSpeakersDelayActionsStorage::removeAllTimers() { - LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin(); - for (; iter != mActionTimersMap.end(); ++iter) - { - delete iter->second; - } - mActionTimersMap.clear(); + LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin(); + for (; iter != mActionTimersMap.end(); ++iter) + { + delete iter->second; + } + mActionTimersMap.clear(); } bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_id) { - unsetActionTimer(speaker_id); + unsetActionTimer(speaker_id); - if (mActionCallback) - { - mActionCallback(speaker_id); - } + if (mActionCallback) + { + mActionCallback(speaker_id); + } - return true; + return true; } bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id) { - return (mActionTimersMap.size() > 0) && (mActionTimersMap.find(speaker_id) != mActionTimersMap.end()); + return (mActionTimersMap.size() > 0) && (mActionTimersMap.find(speaker_id) != mActionTimersMap.end()); } // // LLSpeakerMgr // -LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : - mVoiceChannel(channelp), - mVoiceModerated(false), - mModerateModeHandledFirstTime(false), - mSpeakerListUpdated(false) +LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : + mVoiceChannel(channelp), + mVoiceModerated(false), + mModerateModeHandledFirstTime(false), + mSpeakerListUpdated(false) { mGetListTime.reset(); - static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); + static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); - mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); + mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); } LLSpeakerMgr::~LLSpeakerMgr() { - delete mSpeakerDelayRemover; + delete mSpeakerDelayRemover; } LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) { - LLUUID session_id = getSessionID(); - if (id.isNull() || (id == session_id)) - { - return NULL; - } - - LLPointer speakerp; - if (mSpeakers.find(id) == mSpeakers.end()) - { - speakerp = new LLSpeaker(id, name, type); - speakerp->mStatus = status; - mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); - mSpeakersSorted.push_back(speakerp); - LL_DEBUGS("Speakers") << "Added speaker " << id << LL_ENDL; - fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); - } - else - { - speakerp = findSpeaker(id); - if (speakerp.notNull()) - { - // keep highest priority status (lowest value) instead of overriding current value - speakerp->mStatus = llmin(speakerp->mStatus, status); - // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id - // we need to override speakers that we think are objects when we find out they are really - // residents - if (type == LLSpeaker::SPEAKER_AGENT) - { - speakerp->mType = LLSpeaker::SPEAKER_AGENT; - speakerp->lookupName(); - } - } - else - { - LL_WARNS("Speakers") << "Speaker " << id << " not found" << LL_ENDL; - } - } - - mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); - return speakerp; + LLUUID session_id = getSessionID(); + if (id.isNull() || (id == session_id)) + { + return NULL; + } + + LLPointer speakerp; + if (mSpeakers.find(id) == mSpeakers.end()) + { + speakerp = new LLSpeaker(id, name, type); + speakerp->mStatus = status; + mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); + mSpeakersSorted.push_back(speakerp); + LL_DEBUGS("Speakers") << "Added speaker " << id << LL_ENDL; + fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); + } + else + { + speakerp = findSpeaker(id); + if (speakerp.notNull()) + { + // keep highest priority status (lowest value) instead of overriding current value + speakerp->mStatus = llmin(speakerp->mStatus, status); + // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id + // we need to override speakers that we think are objects when we find out they are really + // residents + if (type == LLSpeaker::SPEAKER_AGENT) + { + speakerp->mType = LLSpeaker::SPEAKER_AGENT; + speakerp->lookupName(); + } + } + else + { + LL_WARNS("Speakers") << "Speaker " << id << " not found" << LL_ENDL; + } + } + + mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); + return speakerp; } // *TODO: Once way to request the current voice channel moderation mode is implemented // this method with related code should be removed. /* Initializes "moderate_mode" of voice session on first join. - + This is WORKAROUND because a way to request the current voice channel moderation mode exists but is not implemented in viewer yet. See EXT-6937. */ void LLSpeakerMgr::initVoiceModerateMode() { - if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive())) - { - LLPointer speakerp; - - if (mSpeakers.find(gAgentID) != mSpeakers.end()) - { - speakerp = mSpeakers[gAgentID]; - } - - if (speakerp.notNull()) - { - mVoiceModerated = speakerp->mModeratorMutedVoice; - mModerateModeHandledFirstTime = true; - } - } + if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive())) + { + LLPointer speakerp; + + if (mSpeakers.find(gAgentID) != mSpeakers.end()) + { + speakerp = mSpeakers[gAgentID]; + } + + if (speakerp.notNull()) + { + mVoiceModerated = speakerp->mModeratorMutedVoice; + mModerateModeHandledFirstTime = true; + } + } } void LLSpeakerMgr::update(BOOL resort_ok) { - if (!LLVoiceClient::getInstance()) - { - return; - } - - LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor"); - LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor"); - - if(resort_ok) // only allow list changes when user is not interacting with it - { - updateSpeakerList(); - } - - // update status of all current speakers - BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) - { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; - - if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) - { - speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); - BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); - if (moderator_muted_voice != speakerp->mModeratorMutedVoice) - { - speakerp->mModeratorMutedVoice = moderator_muted_voice; - LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< LL_ENDL; - speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); - } - - if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) - { - speakerp->mStatus = LLSpeaker::STATUS_MUTED; - } - else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) - { - // reset inactivity expiration - if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) - { - speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); - speakerp->mHasSpoken = TRUE; - fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); - } - speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; - // interpolate between active color and full speaking color based on power of speech output - speakerp->mDotColor = speaking_color; - if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) - { - speakerp->mDotColor = overdriven_color; - } - } - else - { - speakerp->mSpeechVolume = 0.f; - speakerp->mDotColor = ACTIVE_COLOR; - - if (speakerp->mHasSpoken) - { - // have spoken once, not currently speaking - speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; - } - else - { - // default state for being in voice channel - speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; - } - } - } - // speaker no longer registered in voice channel, demote to text only - else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL) - { - if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) - { - // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - } - else - { - speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; - speakerp->mSpeechVolume = 0.f; - speakerp->mDotColor = ACTIVE_COLOR; - } - } - } - - if(resort_ok) // only allow list changes when user is not interacting with it - { - // sort by status then time last spoken - std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); - } - - // for recent speakers who are not currently speaking, show "recent" color dot for most recent - // fading to "active" color - - S32 recent_speaker_count = 0; - S32 sort_index = 0; - speaker_list_t::iterator sorted_speaker_it; - for(sorted_speaker_it = mSpeakersSorted.begin(); - sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) - { - LLPointer speakerp = *sorted_speaker_it; - - // color code recent speakers who are not currently speaking - if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) - { - speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); - recent_speaker_count++; - } - - // stuff sort ordinal into speaker so the ui can sort by this value - speakerp->mSortIndex = sort_index++; - } + if (!LLVoiceClient::getInstance()) + { + return; + } + + LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor"); + LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor"); + + if(resort_ok) // only allow list changes when user is not interacting with it + { + updateSpeakerList(); + } + + // update status of all current speakers + BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) + { + LLUUID speaker_id = speaker_it->first; + LLSpeaker* speakerp = speaker_it->second; + + if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) + { + speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); + BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); + if (moderator_muted_voice != speakerp->mModeratorMutedVoice) + { + speakerp->mModeratorMutedVoice = moderator_muted_voice; + LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< LL_ENDL; + speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); + } + + if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) + { + speakerp->mStatus = LLSpeaker::STATUS_MUTED; + } + else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) + { + // reset inactivity expiration + if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) + { + speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); + speakerp->mHasSpoken = TRUE; + fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); + } + speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; + // interpolate between active color and full speaking color based on power of speech output + speakerp->mDotColor = speaking_color; + if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) + { + speakerp->mDotColor = overdriven_color; + } + } + else + { + speakerp->mSpeechVolume = 0.f; + speakerp->mDotColor = ACTIVE_COLOR; + + if (speakerp->mHasSpoken) + { + // have spoken once, not currently speaking + speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; + } + else + { + // default state for being in voice channel + speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; + } + } + } + // speaker no longer registered in voice channel, demote to text only + else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL) + { + if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) + { + // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + } + else + { + speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; + speakerp->mSpeechVolume = 0.f; + speakerp->mDotColor = ACTIVE_COLOR; + } + } + } + + if(resort_ok) // only allow list changes when user is not interacting with it + { + // sort by status then time last spoken + std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); + } + + // for recent speakers who are not currently speaking, show "recent" color dot for most recent + // fading to "active" color + + S32 recent_speaker_count = 0; + S32 sort_index = 0; + speaker_list_t::iterator sorted_speaker_it; + for(sorted_speaker_it = mSpeakersSorted.begin(); + sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) + { + LLPointer speakerp = *sorted_speaker_it; + + // color code recent speakers who are not currently speaking + if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) + { + speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); + recent_speaker_count++; + } + + // stuff sort ordinal into speaker so the ui can sort by this value + speakerp->mSortIndex = sort_index++; + } } void LLSpeakerMgr::updateSpeakerList() { - // Are we bound to the currently active voice channel? - if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) - { - std::set participants; - LLVoiceClient::getInstance()->getParticipantList(participants); - // If we are, add all voice client participants to our list of known speakers - for (std::set::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) - { - setSpeaker(*participant_it, - LLVoiceClient::getInstance()->getDisplayName(*participant_it), - LLSpeaker::STATUS_VOICE_ACTIVE, - (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); - } - } - else - { - // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). - LLUUID session_id = getSessionID(); - if (!session_id.isNull() && !mSpeakerListUpdated) - { - // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long. - // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started. - // (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply) - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); - if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) - { - // For groups, we need to hit the group manager. - // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); - - if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) - { - // Add group members when we get the complete list (note: can take a while before we get that list) - LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); + // Are we bound to the currently active voice channel? + if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) + { + std::set participants; + LLVoiceClient::getInstance()->getParticipantList(participants); + // If we are, add all voice client participants to our list of known speakers + for (std::set::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) + { + setSpeaker(*participant_it, + LLVoiceClient::getInstance()->getDisplayName(*participant_it), + LLSpeaker::STATUS_VOICE_ACTIVE, + (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); + } + } + else + { + // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). + LLUUID session_id = getSessionID(); + if (!session_id.isNull() && !mSpeakerListUpdated) + { + // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long. + // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started. + // (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply) + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) + { + // For groups, we need to hit the group manager. + // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); + + if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + { + // Add group members when we get the complete list (note: can take a while before we get that list) + LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); const S32 load_group_max_members = gSavedSettings.getS32("ChatLoadGroupMaxMembers"); S32 updated = 0; - while (member_it != gdatap->mMembers.end()) - { - LLGroupMemberData* member = member_it->second; + while (member_it != gdatap->mMembers.end()) + { + LLGroupMemberData* member = member_it->second; LLUUID id = member_it->first; - // Add only members who are online and not already in the list - if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end())) - { - LLPointer speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); - speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); + // Add only members who are online and not already in the list + if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end())) + { + LLPointer speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); updated++; - } - ++member_it; + } + ++member_it; // Limit the number of "manually updated" participants to a reasonable number to avoid severe fps drop // *TODO : solve the perf issue of having several hundreds of widgets in the conversation list if (updated >= load_group_max_members) break; - } + } mSpeakerListUpdated = true; - } - } - else if (mSpeakers.size() == 0) - { - // For all other session type (ad-hoc, P2P), we use the initial participants targets list - for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it) - { - // Add buddies if they are on line, add any other avatar. - if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it)) - { - setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); - } - } - mSpeakerListUpdated = true; - } - else - { - // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server) - mSpeakerListUpdated = true; - } - } - } - // Always add the current agent (it has to be there...). Will do nothing if already there. - setSpeaker(gAgentID, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + } + } + else if (mSpeakers.size() == 0) + { + // For all other session type (ad-hoc, P2P), we use the initial participants targets list + for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it) + { + // Add buddies if they are on line, add any other avatar. + if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it)) + { + setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + } + } + mSpeakerListUpdated = true; + } + else + { + // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server) + mSpeakerListUpdated = true; + } + } + } + // Always add the current agent (it has to be there...). Will do nothing if already there. + setSpeaker(gAgentID, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); } void LLSpeakerMgr::setSpeakerNotInChannel(LLPointer speakerp) { - if (speakerp.notNull()) - { - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - speakerp->mDotColor = INACTIVE_COLOR; - mSpeakerDelayRemover->setActionTimer(speakerp->mID); - } + if (speakerp.notNull()) + { + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + speakerp->mDotColor = INACTIVE_COLOR; + mSpeakerDelayRemover->setActionTimer(speakerp->mID); + } } bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) { - mSpeakers.erase(speaker_id); + mSpeakers.erase(speaker_id); - speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); - - for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) - { - if (speaker_id == (*sorted_speaker_it)->mID) - { - mSpeakersSorted.erase(sorted_speaker_it); - break; - } - } + speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); - LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << LL_ENDL; - fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); + for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) + { + if (speaker_id == (*sorted_speaker_it)->mID) + { + mSpeakersSorted.erase(sorted_speaker_it); + break; + } + } + + LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << LL_ENDL; + fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); - update(TRUE); + update(TRUE); - return false; + return false; } LLPointer LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) { - //In some conditions map causes crash if it is empty(Windows only), adding check (EK) - if (mSpeakers.size() == 0) - return NULL; - speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); - if (found_it == mSpeakers.end()) - { - return NULL; - } - return found_it->second; + //In some conditions map causes crash if it is empty(Windows only), adding check (EK) + if (mSpeakers.size() == 0) + return NULL; + speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); + if (found_it == mSpeakers.end()) + { + return NULL; + } + return found_it->second; } void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text) { - speaker_list->clear(); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLPointer speakerp = speaker_it->second; - // what about text only muted or inactive? - if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) - { - speaker_list->push_back(speakerp); - } - } + speaker_list->clear(); + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLPointer speakerp = speaker_it->second; + // what about text only muted or inactive? + if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) + { + speaker_list->push_back(speakerp); + } + } } -const LLUUID LLSpeakerMgr::getSessionID() -{ - return mVoiceChannel->getSessionID(); +const LLUUID LLSpeakerMgr::getSessionID() +{ + return mVoiceChannel->getSessionID(); } bool LLSpeakerMgr::isSpeakerToBeRemoved(const LLUUID& speaker_id) { - return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id); + return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id); } void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing) { - LLPointer speakerp = findSpeaker(speaker_id); - if (speakerp.notNull()) - { - speakerp->mTyping = typing; - } + LLPointer speakerp = findSpeaker(speaker_id); + if (speakerp.notNull()) + { + speakerp->mTyping = typing; + } } // speaker has chatted via either text or voice void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id) { - LLPointer speakerp = findSpeaker(speaker_id); - if (speakerp.notNull()) - { - speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); - speakerp->mHasSpoken = TRUE; - fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); - } + LLPointer speakerp = findSpeaker(speaker_id); + if (speakerp.notNull()) + { + speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); + speakerp->mHasSpoken = TRUE; + fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); + } } BOOL LLSpeakerMgr::isVoiceActive() { - // mVoiceChannel = NULL means current voice channel, whatever it is - return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); + // mVoiceChannel = NULL means current voice channel, whatever it is + return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); } @@ -663,170 +663,170 @@ LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel) void LLIMSpeakerMgr::updateSpeakerList() { - // don't do normal updates which are pulled from voice channel - // rely on user list reported by sim - - // We need to do this to allow PSTN callers into group chats to show in the list. - LLSpeakerMgr::updateSpeakerList(); - - return; + // don't do normal updates which are pulled from voice channel + // rely on user list reported by sim + + // We need to do this to allow PSTN callers into group chats to show in the list. + LLSpeakerMgr::updateSpeakerList(); + + return; } void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers) { - if ( !speakers.isMap() ) return; - - if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) - { - LLSD::map_const_iterator speaker_it; - for(speaker_it = speakers["agent_info"].beginMap(); - speaker_it != speakers["agent_info"].endMap(); - ++speaker_it) - { - LLUUID agent_id(speaker_it->first); - - LLPointer speakerp = setSpeaker( - agent_id, - LLStringUtil::null, - LLSpeaker::STATUS_TEXT_ONLY); - - if ( speaker_it->second.isMap() ) - { - BOOL is_moderator = speakerp->mIsModerator; - speakerp->mIsModerator = speaker_it->second["is_moderator"]; - speakerp->mModeratorMutedText = - speaker_it->second["mutes"]["text"]; - // Fire event only if moderator changed - if ( is_moderator != speakerp->mIsModerator ) - { - LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; - fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); - } - } - } - } - else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) - { - //older, more decprecated way. Need here for - //using older version of servers - LLSD::array_const_iterator speaker_it; - for(speaker_it = speakers["agents"].beginArray(); - speaker_it != speakers["agents"].endArray(); - ++speaker_it) - { - const LLUUID agent_id = (*speaker_it).asUUID(); - - LLPointer speakerp = setSpeaker( - agent_id, - LLStringUtil::null, - LLSpeaker::STATUS_TEXT_ONLY); - } - } + if ( !speakers.isMap() ) return; + + if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) + { + LLSD::map_const_iterator speaker_it; + for(speaker_it = speakers["agent_info"].beginMap(); + speaker_it != speakers["agent_info"].endMap(); + ++speaker_it) + { + LLUUID agent_id(speaker_it->first); + + LLPointer speakerp = setSpeaker( + agent_id, + LLStringUtil::null, + LLSpeaker::STATUS_TEXT_ONLY); + + if ( speaker_it->second.isMap() ) + { + BOOL is_moderator = speakerp->mIsModerator; + speakerp->mIsModerator = speaker_it->second["is_moderator"]; + speakerp->mModeratorMutedText = + speaker_it->second["mutes"]["text"]; + // Fire event only if moderator changed + if ( is_moderator != speakerp->mIsModerator ) + { + LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; + fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); + } + } + } + } + else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) + { + //older, more decprecated way. Need here for + //using older version of servers + LLSD::array_const_iterator speaker_it; + for(speaker_it = speakers["agents"].beginArray(); + speaker_it != speakers["agents"].endArray(); + ++speaker_it) + { + const LLUUID agent_id = (*speaker_it).asUUID(); + + LLPointer speakerp = setSpeaker( + agent_id, + LLStringUtil::null, + LLSpeaker::STATUS_TEXT_ONLY); + } + } } void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) { - if ( !update.isMap() ) return; - - if ( update.has("agent_updates") && update["agent_updates"].isMap() ) - { - LLSD::map_const_iterator update_it; - for( - update_it = update["agent_updates"].beginMap(); - update_it != update["agent_updates"].endMap(); - ++update_it) - { - LLUUID agent_id(update_it->first); - LLPointer speakerp = findSpeaker(agent_id); - - LLSD agent_data = update_it->second; - - if (agent_data.isMap() && agent_data.has("transition")) - { - if (agent_data["transition"].asString() == "LEAVE") - { - setSpeakerNotInChannel(speakerp); - } - else if (agent_data["transition"].asString() == "ENTER") - { - // add or update speaker - speakerp = setSpeaker(agent_id); - } - else - { - LL_WARNS() << "bad membership list update from 'agent_updates' for agent " << agent_id << ", transition " << ll_print_sd(agent_data["transition"]) << LL_ENDL; - } - } - - if (speakerp.isNull()) continue; - - // should have a valid speaker from this point on - if (agent_data.isMap() && agent_data.has("info")) - { - LLSD agent_info = agent_data["info"]; - - if (agent_info.has("is_moderator")) - { - BOOL is_moderator = speakerp->mIsModerator; - speakerp->mIsModerator = agent_info["is_moderator"]; - // Fire event only if moderator changed - if ( is_moderator != speakerp->mIsModerator ) - { - LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; - fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); - } - } - - if (agent_info.has("mutes")) - { - speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; - } - } - } - } - else if ( update.has("updates") && update["updates"].isMap() ) - { - LLSD::map_const_iterator update_it; - for ( - update_it = update["updates"].beginMap(); - update_it != update["updates"].endMap(); - ++update_it) - { - LLUUID agent_id(update_it->first); - LLPointer speakerp = findSpeaker(agent_id); - - std::string agent_transition = update_it->second.asString(); - if (agent_transition == "LEAVE") - { - setSpeakerNotInChannel(speakerp); - } - else if ( agent_transition == "ENTER") - { - // add or update speaker - speakerp = setSpeaker(agent_id); - } - else - { - LL_WARNS() << "bad membership list update from 'updates' for agent " << agent_id << ", transition " << agent_transition << LL_ENDL; - } - } - } + if ( !update.isMap() ) return; + + if ( update.has("agent_updates") && update["agent_updates"].isMap() ) + { + LLSD::map_const_iterator update_it; + for( + update_it = update["agent_updates"].beginMap(); + update_it != update["agent_updates"].endMap(); + ++update_it) + { + LLUUID agent_id(update_it->first); + LLPointer speakerp = findSpeaker(agent_id); + + LLSD agent_data = update_it->second; + + if (agent_data.isMap() && agent_data.has("transition")) + { + if (agent_data["transition"].asString() == "LEAVE") + { + setSpeakerNotInChannel(speakerp); + } + else if (agent_data["transition"].asString() == "ENTER") + { + // add or update speaker + speakerp = setSpeaker(agent_id); + } + else + { + LL_WARNS() << "bad membership list update from 'agent_updates' for agent " << agent_id << ", transition " << ll_print_sd(agent_data["transition"]) << LL_ENDL; + } + } + + if (speakerp.isNull()) continue; + + // should have a valid speaker from this point on + if (agent_data.isMap() && agent_data.has("info")) + { + LLSD agent_info = agent_data["info"]; + + if (agent_info.has("is_moderator")) + { + BOOL is_moderator = speakerp->mIsModerator; + speakerp->mIsModerator = agent_info["is_moderator"]; + // Fire event only if moderator changed + if ( is_moderator != speakerp->mIsModerator ) + { + LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL; + fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); + } + } + + if (agent_info.has("mutes")) + { + speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; + } + } + } + } + else if ( update.has("updates") && update["updates"].isMap() ) + { + LLSD::map_const_iterator update_it; + for ( + update_it = update["updates"].beginMap(); + update_it != update["updates"].endMap(); + ++update_it) + { + LLUUID agent_id(update_it->first); + LLPointer speakerp = findSpeaker(agent_id); + + std::string agent_transition = update_it->second.asString(); + if (agent_transition == "LEAVE") + { + setSpeakerNotInChannel(speakerp); + } + else if ( agent_transition == "ENTER") + { + // add or update speaker + speakerp = setSpeaker(agent_id); + } + else + { + LL_WARNS() << "bad membership list update from 'updates' for agent " << agent_id << ", transition " << agent_transition << LL_ENDL; + } + } + } } void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { - LLPointer speakerp = findSpeaker(speaker_id); - if (!speakerp) return; - - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "mute update"; - data["session-id"] = getSessionID(); - data["params"] = LLSD::emptyMap(); - data["params"]["agent_id"] = speaker_id; - data["params"]["mute_info"] = LLSD::emptyMap(); - //current value represents ability to type, so invert - data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; + LLPointer speakerp = findSpeaker(speaker_id); + if (!speakerp) return; + + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "mute update"; + data["session-id"] = getSessionID(); + data["params"] = LLSD::emptyMap(); + data["params"]["agent_id"] = speaker_id; + data["params"]["mute_info"] = LLSD::emptyMap(); + //current value represents ability to type, so invert + data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); @@ -834,24 +834,24 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute) { - LLPointer speakerp = findSpeaker(avatar_id); - if (!speakerp) return; + LLPointer speakerp = findSpeaker(avatar_id); + if (!speakerp) return; - // *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for - // text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) - bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED; + // *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for + // text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) + bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED; - // do not send voice moderation changes for avatars not in voice channel - if (!is_in_voice) return; + // do not send voice moderation changes for avatars not in voice channel + if (!is_in_voice) return; - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "mute update"; - data["session-id"] = getSessionID(); - data["params"] = LLSD::emptyMap(); - data["params"]["agent_id"] = avatar_id; - data["params"]["mute_info"] = LLSD::emptyMap(); - data["params"]["mute_info"]["voice"] = !unmute; + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "mute update"; + data["session-id"] = getSessionID(); + data["params"] = LLSD::emptyMap(); + data["params"]["agent_id"] = avatar_id; + data["params"]["mute_info"] = LLSD::emptyMap(); + data["params"]["mute_info"]["voice"] = !unmute; LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); @@ -901,39 +901,39 @@ void LLIMSpeakerMgr::moderationActionCoro(std::string url, LLSD action) void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone ) { - if (mVoiceModerated == !unmute_everyone) - { - // session already in requested state. Just force participants which do not match it. - forceVoiceModeratedMode(mVoiceModerated); - } - else - { - // otherwise set moderated mode for a whole session. - moderateVoiceSession(getSessionID(), !unmute_everyone); - } + if (mVoiceModerated == !unmute_everyone) + { + // session already in requested state. Just force participants which do not match it. + forceVoiceModeratedMode(mVoiceModerated); + } + else + { + // otherwise set moderated mode for a whole session. + moderateVoiceSession(getSessionID(), !unmute_everyone); + } } void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update) { - if (session_update.has("moderated_mode") && - session_update["moderated_mode"].has("voice")) - { - mVoiceModerated = session_update["moderated_mode"]["voice"]; - } + if (session_update.has("moderated_mode") && + session_update["moderated_mode"].has("voice")) + { + mVoiceModerated = session_update["moderated_mode"]["voice"]; + } } void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice) { - std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "session update"; - data["session-id"] = session_id; - data["params"] = LLSD::emptyMap(); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "session update"; + data["session-id"] = session_id; + data["params"] = LLSD::emptyMap(); - data["params"]["update_info"] = LLSD::emptyMap(); + data["params"]["update_info"] = LLSD::emptyMap(); - data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap(); - data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; + data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap(); + data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); @@ -941,17 +941,17 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted) { - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; - - // participant does not match requested state - if (should_be_muted != (bool)speakerp->mModeratorMutedVoice) - { - moderateVoiceParticipant(speaker_id, !should_be_muted); - } - } + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLUUID speaker_id = speaker_it->first; + LLSpeaker* speakerp = speaker_it->second; + + // participant does not match requested state + if (should_be_muted != (bool)speakerp->mModeratorMutedVoice) + { + moderateVoiceParticipant(speaker_id, !should_be_muted); + } + } } // @@ -964,31 +964,31 @@ LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL) void LLActiveSpeakerMgr::updateSpeakerList() { - // point to whatever the current voice channel is - mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); - - // always populate from active voice channel - if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false - { - LL_DEBUGS("Speakers") << "Removed all speakers" << LL_ENDL; - fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); - mSpeakers.clear(); - mSpeakersSorted.clear(); - mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); - mSpeakerDelayRemover->removeAllTimers(); - } - LLSpeakerMgr::updateSpeakerList(); - - // clean up text only speakers - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) - { - LLSpeaker* speakerp = speaker_it->second; - if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) - { - // automatically flag text only speakers for removal - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - } - } + // point to whatever the current voice channel is + mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + + // always populate from active voice channel + if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false + { + LL_DEBUGS("Speakers") << "Removed all speakers" << LL_ENDL; + fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); + mSpeakers.clear(); + mSpeakersSorted.clear(); + mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + mSpeakerDelayRemover->removeAllTimers(); + } + LLSpeakerMgr::updateSpeakerList(); + + // clean up text only speakers + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + { + LLSpeaker* speakerp = speaker_it->second; + if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) + { + // automatically flag text only speakers for removal + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + } + } } @@ -1008,35 +1008,35 @@ LLLocalSpeakerMgr::~LLLocalSpeakerMgr () void LLLocalSpeakerMgr::updateSpeakerList() { - // pull speakers from voice channel - LLSpeakerMgr::updateSpeakerList(); - - if (gDisconnected)//the world is cleared. - { - return ; - } - - // pick up non-voice speakers in chat range - uuid_vec_t avatar_ids; - std::vector positions; - LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); - for(U32 i=0; ifirst; - LLPointer speakerp = speaker_it->second; - if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) - { - LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); - if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS) - { - setSpeakerNotInChannel(speakerp); - } - } - } + // pull speakers from voice channel + LLSpeakerMgr::updateSpeakerList(); + + if (gDisconnected)//the world is cleared. + { + return ; + } + + // pick up non-voice speakers in chat range + uuid_vec_t avatar_ids; + std::vector positions; + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); + for(U32 i=0; ifirst; + LLPointer speakerp = speaker_it->second; + if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) + { + LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); + if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS) + { + setSpeakerNotInChannel(speakerp); + } + } + } } diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 0242da1605..234de42953 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -1,25 +1,25 @@ -/** +/** * @file llspeakers.h * @brief Management interface for muting and controlling volume of residents currently speaking * * $LicenseInfo:firstyear=2005&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$ */ @@ -40,94 +40,94 @@ class LLAvatarName; class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider, public boost::signals2::trackable { public: - typedef enum e_speaker_type - { - SPEAKER_AGENT, - SPEAKER_OBJECT, - SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group) - } ESpeakerType; - - typedef enum e_speaker_status - { - STATUS_SPEAKING, - STATUS_HAS_SPOKEN, - STATUS_VOICE_ACTIVE, - STATUS_TEXT_ONLY, - STATUS_NOT_IN_CHANNEL, - STATUS_MUTED - } ESpeakerStatus; - - - LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); - ~LLSpeaker() {}; - void lookupName(); - - void onNameCache(const LLUUID& id, const LLAvatarName& full_name); - - bool isInVoiceChannel(); - - ESpeakerStatus mStatus; // current activity status in speech group - F32 mLastSpokeTime; // timestamp when this speaker last spoke - F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?) - std::string mDisplayName; // cache user name for this speaker - BOOL mHasSpoken; // has this speaker said anything this session? - BOOL mHasLeftCurrentCall; // has this speaker left the current voice call? - LLColor4 mDotColor; - LLUUID mID; - BOOL mTyping; - S32 mSortIndex; - ESpeakerType mType; - BOOL mIsModerator; - BOOL mModeratorMutedVoice; - BOOL mModeratorMutedText; + typedef enum e_speaker_type + { + SPEAKER_AGENT, + SPEAKER_OBJECT, + SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group) + } ESpeakerType; + + typedef enum e_speaker_status + { + STATUS_SPEAKING, + STATUS_HAS_SPOKEN, + STATUS_VOICE_ACTIVE, + STATUS_TEXT_ONLY, + STATUS_NOT_IN_CHANNEL, + STATUS_MUTED + } ESpeakerStatus; + + + LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); + ~LLSpeaker() {}; + void lookupName(); + + void onNameCache(const LLUUID& id, const LLAvatarName& full_name); + + bool isInVoiceChannel(); + + ESpeakerStatus mStatus; // current activity status in speech group + F32 mLastSpokeTime; // timestamp when this speaker last spoke + F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?) + std::string mDisplayName; // cache user name for this speaker + BOOL mHasSpoken; // has this speaker said anything this session? + BOOL mHasLeftCurrentCall; // has this speaker left the current voice call? + LLColor4 mDotColor; + LLUUID mID; + BOOL mTyping; + S32 mSortIndex; + ESpeakerType mType; + BOOL mIsModerator; + BOOL mModeratorMutedVoice; + BOOL mModeratorMutedText; }; class LLSpeakerUpdateSpeakerEvent : public LLOldEvents::LLEvent { public: - LLSpeakerUpdateSpeakerEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerUpdateSpeakerEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); private: - const LLUUID& mSpeakerID; + const LLUUID& mSpeakerID; }; class LLSpeakerUpdateModeratorEvent : public LLOldEvents::LLEvent { public: - LLSpeakerUpdateModeratorEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerUpdateModeratorEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); private: - const LLUUID& mSpeakerID; - BOOL mIsModerator; + const LLUUID& mSpeakerID; + BOOL mIsModerator; }; class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent { public: - LLSpeakerTextModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerTextModerationEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); }; class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent { public: - LLSpeakerVoiceModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + LLSpeakerVoiceModerationEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue(); }; class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent { public: - LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); - /*virtual*/ LLSD getValue(); + LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); + /*virtual*/ LLSD getValue(); private: - const LLUUID& mSpeakerID; + const LLUUID& mSpeakerID; }; /** * class LLSpeakerActionTimer - * + * * Implements a timer that calls stored callback action for stored speaker after passed period. * * Action is called until callback returns "true". @@ -138,39 +138,39 @@ private: class LLSpeakerActionTimer : public LLEventTimer { public: - typedef boost::function action_callback_t; - typedef std::map action_timers_map_t; - typedef action_timers_map_t::value_type action_value_t; - typedef action_timers_map_t::const_iterator action_timer_const_iter_t; - typedef action_timers_map_t::iterator action_timer_iter_t; - - /** - * Constructor. - * - * @param action_cb - callback which will be called each time after passed action period. - * @param action_period - time in seconds timer should tick. - * @param speaker_id - LLUUID of speaker which will be passed into action callback. - */ - LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); - virtual ~LLSpeakerActionTimer() {}; - - /** - * Implements timer "tick". - * - * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). - */ - bool tick() override; - - /** - * Clears the callback. - * - * Use this instead of deleteing this object. - * The next call to tick() will return true and that will destroy this object. - */ - void unset(); + typedef boost::function action_callback_t; + typedef std::map action_timers_map_t; + typedef action_timers_map_t::value_type action_value_t; + typedef action_timers_map_t::const_iterator action_timer_const_iter_t; + typedef action_timers_map_t::iterator action_timer_iter_t; + + /** + * Constructor. + * + * @param action_cb - callback which will be called each time after passed action period. + * @param action_period - time in seconds timer should tick. + * @param speaker_id - LLUUID of speaker which will be passed into action callback. + */ + LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); + virtual ~LLSpeakerActionTimer() {}; + + /** + * Implements timer "tick". + * + * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). + */ + bool tick() override; + + /** + * Clears the callback. + * + * Use this instead of deleteing this object. + * The next call to tick() will return true and that will destroy this object. + */ + void unset(); private: - action_callback_t mActionCallback; - LLUUID mSpeakerId; + action_callback_t mActionCallback; + LLUUID mSpeakerId; }; /** @@ -180,153 +180,153 @@ private: class LLSpeakersDelayActionsStorage { public: - LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay); - ~LLSpeakersDelayActionsStorage(); + LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay); + ~LLSpeakersDelayActionsStorage(); - /** - * Sets new LLSpeakerActionTimer with passed speaker UUID. - */ - void setActionTimer(const LLUUID& speaker_id); + /** + * Sets new LLSpeakerActionTimer with passed speaker UUID. + */ + void setActionTimer(const LLUUID& speaker_id); - /** - * Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and optionally deletes it. - * - * @see onTimerActionCallback() - */ - void unsetActionTimer(const LLUUID& speaker_id); + /** + * Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and optionally deletes it. + * + * @see onTimerActionCallback() + */ + void unsetActionTimer(const LLUUID& speaker_id); - void removeAllTimers(); + void removeAllTimers(); - bool isTimerStarted(const LLUUID& speaker_id); + bool isTimerStarted(const LLUUID& speaker_id); private: - /** - * Callback of the each instance of LLSpeakerActionTimer. - * - * Unsets an appropriate timer instance and calls action callback for specified speacker_id. - * - * @see unsetActionTimer() - */ - bool onTimerActionCallback(const LLUUID& speaker_id); - - LLSpeakerActionTimer::action_timers_map_t mActionTimersMap; - LLSpeakerActionTimer::action_callback_t mActionCallback; - - /** - * Delay to call action callback for speakers after timer was set. - */ - F32 mActionDelay; + /** + * Callback of the each instance of LLSpeakerActionTimer. + * + * Unsets an appropriate timer instance and calls action callback for specified speacker_id. + * + * @see unsetActionTimer() + */ + bool onTimerActionCallback(const LLUUID& speaker_id); + + LLSpeakerActionTimer::action_timers_map_t mActionTimersMap; + LLSpeakerActionTimer::action_callback_t mActionCallback; + + /** + * Delay to call action callback for speakers after timer was set. + */ + F32 mActionDelay; }; class LLSpeakerMgr : public LLOldEvents::LLObservable { - LOG_CLASS(LLSpeakerMgr); + LOG_CLASS(LLSpeakerMgr); public: - LLSpeakerMgr(LLVoiceChannel* channelp); - virtual ~LLSpeakerMgr(); - - LLPointer findSpeaker(const LLUUID& avatar_id); - void update(BOOL resort_ok); - void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); - void speakerChatted(const LLUUID& speaker_id); - LLPointer setSpeaker(const LLUUID& id, - const std::string& name = LLStringUtil::null, - LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY, - LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); - - BOOL isVoiceActive(); - - typedef std::vector > speaker_list_t; - void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); - LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } - const LLUUID getSessionID(); - bool isSpeakerToBeRemoved(const LLUUID& speaker_id); - - /** - * Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant. - * - * Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937 - */ - void initVoiceModerateMode(); + LLSpeakerMgr(LLVoiceChannel* channelp); + virtual ~LLSpeakerMgr(); + + LLPointer findSpeaker(const LLUUID& avatar_id); + void update(BOOL resort_ok); + void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); + void speakerChatted(const LLUUID& speaker_id); + LLPointer setSpeaker(const LLUUID& id, + const std::string& name = LLStringUtil::null, + LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY, + LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); + + BOOL isVoiceActive(); + + typedef std::vector > speaker_list_t; + void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); + LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } + const LLUUID getSessionID(); + bool isSpeakerToBeRemoved(const LLUUID& speaker_id); + + /** + * Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant. + * + * Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937 + */ + void initVoiceModerateMode(); protected: - virtual void updateSpeakerList(); - void setSpeakerNotInChannel(LLPointer speackerp); - bool removeSpeaker(const LLUUID& speaker_id); + virtual void updateSpeakerList(); + void setSpeakerNotInChannel(LLPointer speackerp); + bool removeSpeaker(const LLUUID& speaker_id); - typedef std::map > speaker_map_t; - speaker_map_t mSpeakers; - bool mSpeakerListUpdated; + typedef std::map > speaker_map_t; + speaker_map_t mSpeakers; + bool mSpeakerListUpdated; LLTimer mGetListTime; - speaker_list_t mSpeakersSorted; - LLFrameTimer mSpeechTimer; - LLVoiceChannel* mVoiceChannel; + speaker_list_t mSpeakersSorted; + LLFrameTimer mSpeechTimer; + LLVoiceChannel* mVoiceChannel; - /** - * time out speakers when they are not part of current session - */ - LLSpeakersDelayActionsStorage* mSpeakerDelayRemover; + /** + * time out speakers when they are not part of current session + */ + LLSpeakersDelayActionsStorage* mSpeakerDelayRemover; - // *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel - // moderation mode is implemented: See EXT-6937 - bool mVoiceModerated; + // *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel + // moderation mode is implemented: See EXT-6937 + bool mVoiceModerated; - // *TODO: To be removed when a way to request the current voice channel - // moderation mode is implemented: See EXT-6937 - bool mModerateModeHandledFirstTime; + // *TODO: To be removed when a way to request the current voice channel + // moderation mode is implemented: See EXT-6937 + bool mModerateModeHandledFirstTime; }; class LLIMSpeakerMgr : public LLSpeakerMgr { - LOG_CLASS(LLIMSpeakerMgr); + LOG_CLASS(LLIMSpeakerMgr); public: - LLIMSpeakerMgr(LLVoiceChannel* channel); - - void updateSpeakers(const LLSD& update); - void setSpeakers(const LLSD& speakers); - - void toggleAllowTextChat(const LLUUID& speaker_id); - - /** - * Mutes/Unmutes avatar for current group voice chat. - * - * It only marks avatar as muted for session and does not use local Agent's Block list. - * It does not mute Agent itself. - * - * @param[in] avatar_id UUID of avatar to be processed - * @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted. - * - * @see moderateVoiceAllParticipants() - */ - void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); - - /** - * Mutes/Unmutes all avatars for current group voice chat. - * - * It only marks avatars as muted for session and does not use local Agent's Block list. - * It calls forceVoiceModeratedMode() in case of session is already in requested state. - * - * @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted. - * - * @see moderateVoiceParticipant() - */ - void moderateVoiceAllParticipants(bool unmute_everyone); - - void processSessionUpdate(const LLSD& session_update); + LLIMSpeakerMgr(LLVoiceChannel* channel); + + void updateSpeakers(const LLSD& update); + void setSpeakers(const LLSD& speakers); + + void toggleAllowTextChat(const LLUUID& speaker_id); + + /** + * Mutes/Unmutes avatar for current group voice chat. + * + * It only marks avatar as muted for session and does not use local Agent's Block list. + * It does not mute Agent itself. + * + * @param[in] avatar_id UUID of avatar to be processed + * @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted. + * + * @see moderateVoiceAllParticipants() + */ + void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); + + /** + * Mutes/Unmutes all avatars for current group voice chat. + * + * It only marks avatars as muted for session and does not use local Agent's Block list. + * It calls forceVoiceModeratedMode() in case of session is already in requested state. + * + * @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted. + * + * @see moderateVoiceParticipant() + */ + void moderateVoiceAllParticipants(bool unmute_everyone); + + void processSessionUpdate(const LLSD& session_update); protected: - virtual void updateSpeakerList(); + virtual void updateSpeakerList(); - void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); + void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); - /** - * Process all participants to mute/unmute them according to passed voice session state. - */ - void forceVoiceModeratedMode(bool should_be_muted); + /** + * Process all participants to mute/unmute them according to passed voice session state. + */ + void forceVoiceModeratedMode(bool should_be_muted); void moderationActionCoro(std::string url, LLSD action); @@ -334,20 +334,20 @@ protected: class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton { - LLSINGLETON(LLActiveSpeakerMgr); - LOG_CLASS(LLActiveSpeakerMgr); + LLSINGLETON(LLActiveSpeakerMgr); + LOG_CLASS(LLActiveSpeakerMgr); protected: - virtual void updateSpeakerList() override; + virtual void updateSpeakerList() override; }; class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton { - LLSINGLETON(LLLocalSpeakerMgr); - ~LLLocalSpeakerMgr (); - LOG_CLASS(LLLocalSpeakerMgr); + LLSINGLETON(LLLocalSpeakerMgr); + ~LLLocalSpeakerMgr (); + LOG_CLASS(LLLocalSpeakerMgr); protected: - virtual void updateSpeakerList() override; + virtual void updateSpeakerList() override; }; #endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a8ba75ab5f..426b71ba67 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstartup.cpp * @brief startup routines. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,9 +31,9 @@ #include "llcallstack.h" #if LL_WINDOWS -# include // _spawnl() +# include // _spawnl() #else -# include // mkdir() +# include // mkdir() #endif #include // std::unique_ptr @@ -84,7 +84,7 @@ #include "llversioninfo.h" #include "llviewercontrol.h" #include "llviewerhelp.h" -#include "llxorcipher.h" // saved password, MAC address +#include "llxorcipher.h" // saved password, MAC address #include "llwindow.h" #include "message.h" #include "v3math.h" @@ -121,7 +121,7 @@ #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" -#include "llloginhandler.h" // gLoginHandler, SLURL support +#include "llloginhandler.h" // gLoginHandler, SLURL support #include "lllogininstance.h" // Host the login module. #include "llpanellogin.h" #include "llmutelist.h" @@ -138,7 +138,7 @@ #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" -#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance +#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance #include "llsurface.h" #include "lltexturecache.h" #include "lltexturefetch.h" @@ -237,7 +237,7 @@ extern S32 gStartImageHeight; // static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; -static std::string sInitialOutfitGender; // "male" or "female" +static std::string sInitialOutfitGender; // "male" or "female" static bool gUseCircuitCallbackCalled = false; @@ -291,12 +291,12 @@ void transition_back_to_login_panel(const std::string& emsg); void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) { - LLNameBox::refreshAll(id, full_name, is_group); - LLNameEditor::refreshAll(id, full_name, is_group); - - // TODO: Actually be intelligent about the refresh. - // For now, just brute force refresh the dialogs. - dialog_refresh_all(); + LLNameBox::refreshAll(id, full_name, is_group); + LLNameEditor::refreshAll(id, full_name, is_group); + + // TODO: Actually be intelligent about the refresh. + // For now, just brute force refresh the dialogs. + dialog_refresh_all(); } // @@ -321,10 +321,10 @@ void pump_idle_startup_network(void) // void update_texture_fetch() { - LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread - LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - gTextureList.updateImages(0.10f); + LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + gTextureList.updateImages(0.10f); if (LLImageGLThread::sEnabledTextures) { @@ -335,8 +335,8 @@ void update_texture_fetch() void set_flags_and_update_appearance() { - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); LLInventoryModelBackgroundFetch::instance().start(); } @@ -345,310 +345,310 @@ void set_flags_and_update_appearance() // true when all initialization done. bool idle_startup() { - if (gViewerWindow == NULL) - { - // We expect window to be initialized - LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; - return false; // No world yet - } - - const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); - static LLTimer timeout; - - static LLTimer login_time; - - // until this is encapsulated, this little hack for the - // auth/transform loop will do. - static F32 progress = 0.10f; - - static std::string auth_desc; - static std::string auth_message; - - static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server - - // last location by default - static S32 agent_location_id = START_LOCATION_ID_LAST; - - static bool show_connect_box = true; - - //static bool stipend_since_login = false; - - // HACK: These are things from the main loop that usually aren't done - // until initialization is complete, but need to be done here for things - // to work. - gIdleCallbacks.callFunctions(); - gViewerWindow->updateUI(); - - LLMortician::updateClass(); - - const std::string delims (" "); - std::string system; - int begIdx, endIdx; - std::string osString = LLOSInfo::instance().getOSStringSimple(); - - begIdx = osString.find_first_not_of (delims); - endIdx = osString.find_first_of (delims, begIdx); - system = osString.substr (begIdx, endIdx - begIdx); - system += "Locale"; - - LLStringUtil::setLocale (LLTrans::getString(system)); - - //note: Removing this line will cause incorrect button size in the login screen. -- bao. - gTextureList.updateImages(0.01f) ; - - if ( STATE_FIRST == LLStartUp::getStartupState() ) - { - static bool first_call = true; - if (first_call) - { - // Other phases get handled when startup state changes, - // need to capture the initial state as well. - LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); - first_call = false; - } - - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - - ///////////////////////////////////////////////// - // - // Initialize stuff that doesn't need data from simulators - // - std::string lastGPU = gSavedSettings.getString("LastGPUString"); - std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); - - if (LLFeatureManager::getInstance()->isSafe()) - { - LLNotificationsUtil::add("DisplaySetToSafe"); - } - else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && - (gSavedSettings.getS32("LastFeatureVersion") != 0)) - { - LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); - } - else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) - { - LLSD subs; - subs["LAST_GPU"] = lastGPU; - subs["THIS_GPU"] = thisGPU; - LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); - } - else if (!gViewerWindow->getInitAlert().empty()) - { - LLNotificationsUtil::add(gViewerWindow->getInitAlert()); - } - - //------------------------------------------------- - // Init the SOCKS 5 proxy if the user has configured - // one. We need to do this early in case the user - // is using SOCKS for HTTP so we get the login - // screen and HTTP tables via SOCKS. - //------------------------------------------------- - LLStartUp::startLLProxy(); - - gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); - gSavedSettings.setString("LastGPUString", thisGPU); - - - std::string xml_file = LLUI::locateSkin("xui_version.xml"); - LLXMLNodePtr root; - bool xml_ok = false; - if (LLXMLNode::parseFile(xml_file, root, NULL)) - { - if( (root->hasName("xui_version") ) ) - { - std::string value = root->getValue(); - F32 version = 0.0f; - LLStringUtil::convertToF32(value, version); - if (version >= 1.0f) - { - xml_ok = true; - } - } - } - if (!xml_ok) - { - // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. - // If that's so, then we'll get a fatal error on attempting to load it, - // which will display a nontranslatable error message that says so. - // Otherwise, we'll display a reasonable error message that IS translatable. - LLAppViewer::instance()->earlyExit("BadInstallation"); - } - // - // Statistics stuff - // - - // Load autopilot and stats stuff - gAgentPilot.load(); - - //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); - - // Load the throttle settings - gViewerThrottle.load(); - - // - // Initialize messaging system - // - LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; - - std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); - - LLFILE* found_template = NULL; - found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ - - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message_template.msg - // file will be located in: - // build-vc**/newview//app_settings - if (!found_template) - { - message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } - #elif LL_DARWIN - // On Mac dev builds, message_template.msg lives in: - // indra/build-*/newview//Second Life/Contents/Resources/app_settings - if (!found_template) - { - message_template_path = - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, - "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } - #endif - - if (found_template) - { - fclose(found_template); - - U32 port = gSavedSettings.getU32("UserConnectionPort"); - - if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) - (gSavedSettings.getBOOL("ConnectionPortEnabled"))) - { - port = gSavedSettings.getU32("ConnectionPort"); - } - - // TODO parameterize - const F32 circuit_heartbeat_interval = 5; - const F32 circuit_timeout = 100; - - const LLUseCircuitCodeResponder* responder = NULL; - bool failure_is_fatal = true; - - if(!start_messaging_system( - message_template_path, - port, - LLVersionInfo::instance().getMajor(), - LLVersionInfo::instance().getMinor(), - LLVersionInfo::instance().getPatch(), - FALSE, - std::string(), - responder, - failure_is_fatal, - circuit_heartbeat_interval, - circuit_timeout)) - { - std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); - LL_WARNS("AppInit") << diagnostic << LL_ENDL; - LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); - } - - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message.xml file will - // be located in indra/build-vc**/newview//app_settings. - std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); - - if (!LLFile::isfile(message_path.c_str())) - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); - } - else - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - } - #else - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - #endif - - } - else - { - LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); - } - - if(gMessageSystem && gMessageSystem->isOK()) - { - // Initialize all of the callbacks in case of bad message - // system data - LLMessageSystem* msg = gMessageSystem; - msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, - invalid_message_callback, - NULL); - msg->setExceptionFunc(MX_PACKET_TOO_SHORT, - invalid_message_callback, - NULL); - - // running off end of a packet is now valid in the case - // when a reader has a newer message template than - // the sender - /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, - invalid_message_callback, - NULL);*/ - msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, - invalid_message_callback, - NULL); - - if (gSavedSettings.getBOOL("LogMessages")) - { - LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; - msg->startLogging(); - } - - // start the xfer system. by default, choke the downloads - // a lot... - const S32 VIEWER_MAX_XFER = 3; - start_xfer_manager(); - gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); - F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); - if (xfer_throttle_bps > 1.f) - { - gXferManager->setUseAckThrottling(TRUE); - gXferManager->setAckThrottleBPS(xfer_throttle_bps); - } - gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); - - - F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); - msg->mPacketRing.setDropPercentage(dropPercent); - - F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); - F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); - if (inBandwidth != 0.f) - { - LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; - msg->mPacketRing.setUseInThrottle(TRUE); - msg->mPacketRing.setInBandwidth(inBandwidth); - } - if (outBandwidth != 0.f) - { - LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; - msg->mPacketRing.setUseOutThrottle(TRUE); - msg->mPacketRing.setOutBandwidth(outBandwidth); - } - } - - LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; - - //------------------------------------------------- - // Init audio, which may be needed for prefs dialog - // or audio cues in connection UI. - //------------------------------------------------- - - if (FALSE == gSavedSettings.getBOOL("NoAudio")) - { - delete gAudiop; - gAudiop = NULL; + if (gViewerWindow == NULL) + { + // We expect window to be initialized + LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; + return false; // No world yet + } + + const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); + static LLTimer timeout; + + static LLTimer login_time; + + // until this is encapsulated, this little hack for the + // auth/transform loop will do. + static F32 progress = 0.10f; + + static std::string auth_desc; + static std::string auth_message; + + static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server + + // last location by default + static S32 agent_location_id = START_LOCATION_ID_LAST; + + static bool show_connect_box = true; + + //static bool stipend_since_login = false; + + // HACK: These are things from the main loop that usually aren't done + // until initialization is complete, but need to be done here for things + // to work. + gIdleCallbacks.callFunctions(); + gViewerWindow->updateUI(); + + LLMortician::updateClass(); + + const std::string delims (" "); + std::string system; + int begIdx, endIdx; + std::string osString = LLOSInfo::instance().getOSStringSimple(); + + begIdx = osString.find_first_not_of (delims); + endIdx = osString.find_first_of (delims, begIdx); + system = osString.substr (begIdx, endIdx - begIdx); + system += "Locale"; + + LLStringUtil::setLocale (LLTrans::getString(system)); + + //note: Removing this line will cause incorrect button size in the login screen. -- bao. + gTextureList.updateImages(0.01f) ; + + if ( STATE_FIRST == LLStartUp::getStartupState() ) + { + static bool first_call = true; + if (first_call) + { + // Other phases get handled when startup state changes, + // need to capture the initial state as well. + LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); + first_call = false; + } + + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + ///////////////////////////////////////////////// + // + // Initialize stuff that doesn't need data from simulators + // + std::string lastGPU = gSavedSettings.getString("LastGPUString"); + std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); + + if (LLFeatureManager::getInstance()->isSafe()) + { + LLNotificationsUtil::add("DisplaySetToSafe"); + } + else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && + (gSavedSettings.getS32("LastFeatureVersion") != 0)) + { + LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); + } + else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) + { + LLSD subs; + subs["LAST_GPU"] = lastGPU; + subs["THIS_GPU"] = thisGPU; + LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); + } + else if (!gViewerWindow->getInitAlert().empty()) + { + LLNotificationsUtil::add(gViewerWindow->getInitAlert()); + } + + //------------------------------------------------- + // Init the SOCKS 5 proxy if the user has configured + // one. We need to do this early in case the user + // is using SOCKS for HTTP so we get the login + // screen and HTTP tables via SOCKS. + //------------------------------------------------- + LLStartUp::startLLProxy(); + + gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); + gSavedSettings.setString("LastGPUString", thisGPU); + + + std::string xml_file = LLUI::locateSkin("xui_version.xml"); + LLXMLNodePtr root; + bool xml_ok = false; + if (LLXMLNode::parseFile(xml_file, root, NULL)) + { + if( (root->hasName("xui_version") ) ) + { + std::string value = root->getValue(); + F32 version = 0.0f; + LLStringUtil::convertToF32(value, version); + if (version >= 1.0f) + { + xml_ok = true; + } + } + } + if (!xml_ok) + { + // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. + // If that's so, then we'll get a fatal error on attempting to load it, + // which will display a nontranslatable error message that says so. + // Otherwise, we'll display a reasonable error message that IS translatable. + LLAppViewer::instance()->earlyExit("BadInstallation"); + } + // + // Statistics stuff + // + + // Load autopilot and stats stuff + gAgentPilot.load(); + + //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); + + // Load the throttle settings + gViewerThrottle.load(); + + // + // Initialize messaging system + // + LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; + + std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); + + LLFILE* found_template = NULL; + found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message_template.msg + // file will be located in: + // build-vc**/newview//app_settings + if (!found_template) + { + message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #elif LL_DARWIN + // On Mac dev builds, message_template.msg lives in: + // indra/build-*/newview//Second Life/Contents/Resources/app_settings + if (!found_template) + { + message_template_path = + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, + "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #endif + + if (found_template) + { + fclose(found_template); + + U32 port = gSavedSettings.getU32("UserConnectionPort"); + + if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) + (gSavedSettings.getBOOL("ConnectionPortEnabled"))) + { + port = gSavedSettings.getU32("ConnectionPort"); + } + + // TODO parameterize + const F32 circuit_heartbeat_interval = 5; + const F32 circuit_timeout = 100; + + const LLUseCircuitCodeResponder* responder = NULL; + bool failure_is_fatal = true; + + if(!start_messaging_system( + message_template_path, + port, + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + FALSE, + std::string(), + responder, + failure_is_fatal, + circuit_heartbeat_interval, + circuit_timeout)) + { + std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); + } + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message.xml file will + // be located in indra/build-vc**/newview//app_settings. + std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); + + if (!LLFile::isfile(message_path.c_str())) + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); + } + else + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + } + #else + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + #endif + + } + else + { + LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); + } + + if(gMessageSystem && gMessageSystem->isOK()) + { + // Initialize all of the callbacks in case of bad message + // system data + LLMessageSystem* msg = gMessageSystem; + msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, + invalid_message_callback, + NULL); + msg->setExceptionFunc(MX_PACKET_TOO_SHORT, + invalid_message_callback, + NULL); + + // running off end of a packet is now valid in the case + // when a reader has a newer message template than + // the sender + /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, + invalid_message_callback, + NULL);*/ + msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, + invalid_message_callback, + NULL); + + if (gSavedSettings.getBOOL("LogMessages")) + { + LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; + msg->startLogging(); + } + + // start the xfer system. by default, choke the downloads + // a lot... + const S32 VIEWER_MAX_XFER = 3; + start_xfer_manager(); + gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); + F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); + if (xfer_throttle_bps > 1.f) + { + gXferManager->setUseAckThrottling(TRUE); + gXferManager->setAckThrottleBPS(xfer_throttle_bps); + } + gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); + + + F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); + msg->mPacketRing.setDropPercentage(dropPercent); + + F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); + F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); + if (inBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; + msg->mPacketRing.setUseInThrottle(TRUE); + msg->mPacketRing.setInBandwidth(inBandwidth); + } + if (outBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; + msg->mPacketRing.setUseOutThrottle(TRUE); + msg->mPacketRing.setOutBandwidth(outBandwidth); + } + } + + LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; + + //------------------------------------------------- + // Init audio, which may be needed for prefs dialog + // or audio cues in connection UI. + //------------------------------------------------- + + if (FALSE == gSavedSettings.getBOOL("NoAudio")) + { + delete gAudiop; + gAudiop = NULL; #ifdef LL_FMODSTUDIO #if !LL_WINDOWS @@ -661,262 +661,262 @@ bool idle_startup() #ifdef LL_OPENAL #if !LL_WINDOWS - if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) + if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) #endif // !LL_WINDOWS - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); - } + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); + } #endif - - if (gAudiop) - { + + if (gAudiop) + { #if LL_WINDOWS - // FMOD Ex on Windows needs the window handle to stop playing audio - // when window is minimized. JC - void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); + // FMOD Ex on Windows needs the window handle to stop playing audio + // when window is minimized. JC + void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); #else - void* window_handle = NULL; + void* window_handle = NULL; #endif - if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) - { - if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) - { - LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); - } - - // if the audio engine hasn't set up its own preferred handler for streaming audio - // then set up the generic streaming audio implementation which uses media plugins - if (NULL == gAudiop->getStreamingAudioImpl()) - { - LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); - } - - gAudiop->setMuted(TRUE); - } - else - { - LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; - delete gAudiop; - gAudiop = NULL; - } - } - } - - LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; - - if (LLTimer::knownBadTimer()) - { - LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; - } - - // - // Log on to system - // - if (gUserCredential.isNull()) - { - gUserCredential = gLoginHandler.initializeLoginInfo(); - } - // Previous initializeLoginInfo may have generated user credentials. Re-check them. - if (gUserCredential.isNull()) - { - show_connect_box = TRUE; - } - else if (gSavedSettings.getBOOL("AutoLogin")) - { - // Log into last account - gRememberPassword = true; - gRememberUser = true; - gSavedSettings.setBOOL("RememberPassword", TRUE); - gSavedSettings.setBOOL("RememberUser", TRUE); - show_connect_box = false; - } - else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) - { - // Console provided login&password - gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); - gRememberUser = gSavedSettings.getBOOL("RememberUser"); - show_connect_box = false; - } - else - { - gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); - gRememberUser = gSavedSettings.getBOOL("RememberUser"); - show_connect_box = TRUE; - } - - //setup map of datetime strings to codes and slt & local time offset from utc - // *TODO: Does this need to be here? - LLStringOps::setupDatetimeInfo(false); - - // Go to the next startup state - LLStartUp::setStartupState( STATE_BROWSER_INIT ); - return FALSE; - } - - - if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingBrowser"); - set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); - // LLViewerMedia::initBrowser(); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - return FALSE; - } - - - if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " - << show_connect_box << LL_ENDL; - - // if we've gone backwards in the login state machine, to this state where we show the UI - // AND the debug setting to exit in this case is true, then go ahead and bail quickly - if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) - { - LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; - // no requirement for notification here - just exit - LLAppViewer::instance()->earlyExitNoNotify(); - } - - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - - // Login screen needs menus for preferences, but we can enter - // this startup phase more than once. - if (gLoginMenuBarView == NULL) - { - LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; - initialize_spellcheck_menu(); - init_menus(); - } - show_release_notes_if_required(); - - if (show_connect_box) - { - LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; - // Load all the name information out of the login view - // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't - // show the login view until login_show() is called below. - if (gUserCredential.isNull()) - { - LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; - gUserCredential = gLoginHandler.initializeLoginInfo(); - } - // Make sure the process dialog doesn't hide things - gViewerWindow->setShowProgress(FALSE); - // Show the login dialog - login_show(); - // connect dialog is already shown, so fill in the names - LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); - LLPanelLogin::giveFocus(); - - // MAINT-3231 Show first run dialog only for Desura viewer - if (gSavedSettings.getString("sourceid") == "1208_desura") - { - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) - { - LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; - show_first_run_dialog(); - } - else - { - LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; - } - } - display_startup(); - LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input - } - else - { - LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; - // skip directly to message template verification - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - } - - gViewerWindow->setNormalControlsVisible( FALSE ); - gLoginMenuBarView->setVisible( TRUE ); - gLoginMenuBarView->setEnabled( TRUE ); - show_debug_menus(); - - // Hide the splash screen - LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; - LLSplashScreen::hide(); - // Push our window frontmost - gViewerWindow->getWindow()->show(); - - // DEV-16927. The following code removes errant keystrokes that happen while the window is being - // first made visible. + if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) + { + if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) + { + LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); + } + + // if the audio engine hasn't set up its own preferred handler for streaming audio + // then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + + gAudiop->setMuted(TRUE); + } + else + { + LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; + delete gAudiop; + gAudiop = NULL; + } + } + } + + LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; + + if (LLTimer::knownBadTimer()) + { + LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; + } + + // + // Log on to system + // + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + // Previous initializeLoginInfo may have generated user credentials. Re-check them. + if (gUserCredential.isNull()) + { + show_connect_box = TRUE; + } + else if (gSavedSettings.getBOOL("AutoLogin")) + { + // Log into last account + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); + show_connect_box = false; + } + else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) + { + // Console provided login&password + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); + show_connect_box = false; + } + else + { + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); + show_connect_box = TRUE; + } + + //setup map of datetime strings to codes and slt & local time offset from utc + // *TODO: Does this need to be here? + LLStringOps::setupDatetimeInfo(false); + + // Go to the next startup state + LLStartUp::setStartupState( STATE_BROWSER_INIT ); + return FALSE; + } + + + if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingBrowser"); + set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + // LLViewerMedia::initBrowser(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + return FALSE; + } + + + if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " + << show_connect_box << LL_ENDL; + + // if we've gone backwards in the login state machine, to this state where we show the UI + // AND the debug setting to exit in this case is true, then go ahead and bail quickly + if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) + { + LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; + // no requirement for notification here - just exit + LLAppViewer::instance()->earlyExitNoNotify(); + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + + // Login screen needs menus for preferences, but we can enter + // this startup phase more than once. + if (gLoginMenuBarView == NULL) + { + LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; + initialize_spellcheck_menu(); + init_menus(); + } + show_release_notes_if_required(); + + if (show_connect_box) + { + LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; + // Load all the name information out of the login view + // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't + // show the login view until login_show() is called below. + if (gUserCredential.isNull()) + { + LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + // Make sure the process dialog doesn't hide things + gViewerWindow->setShowProgress(FALSE); + // Show the login dialog + login_show(); + // connect dialog is already shown, so fill in the names + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); + LLPanelLogin::giveFocus(); + + // MAINT-3231 Show first run dialog only for Desura viewer + if (gSavedSettings.getString("sourceid") == "1208_desura") + { + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; + show_first_run_dialog(); + } + else + { + LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; + } + } + display_startup(); + LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input + } + else + { + LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; + // skip directly to message template verification + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + } + + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + show_debug_menus(); + + // Hide the splash screen + LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; + LLSplashScreen::hide(); + // Push our window frontmost + gViewerWindow->getWindow()->show(); + + // DEV-16927. The following code removes errant keystrokes that happen while the window is being + // first made visible. #ifdef _WIN32 LL_DEBUGS("AppInit") << "Processing PeekMessage" << LL_ENDL; - MSG msg; - while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) + MSG msg; + while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) { } LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL; #endif display_startup(); timeout.reset(); - return FALSE; - } - - if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) - { - // when we get to this state, we've already been past the login UI - // (possiblely automatically) - flag this so we can test in the - // STATE_LOGIN_SHOW state if we've gone backwards - mLoginStatePastUI = true; - - // Don't do anything. Wait for the login view to call the login_callback, - // which will push us to the next state. - - // display() function will be the one to run display_startup() - // Sleep so we don't spin the CPU - ms_sleep(1); - return FALSE; - } - - if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) - { - // Post login screen, we should see if any settings have changed that may - // require us to either start/stop or change the socks proxy. As various communications - // past this point may require the proxy to be up. - if (!LLStartUp::startLLProxy()) - { - // Proxy start up failed, we should now bail the state machine - // startLLProxy() will have reported an error to the user - // already, so we just go back to the login screen. The user - // could then change the preferences to fix the issue. - - LLStartUp::setStartupState(STATE_LOGIN_SHOW); - return FALSE; - } - - // reset the values that could have come in from a slurl - // DEV-42215: Make sure they're not empty -- gUserCredential - // might already have been set from gSavedSettings, and it's too bad - // to overwrite valid values with empty strings. - - if (show_connect_box) - { - // TODO if not use viewer auth - // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); - // end TODO - - // HACK: Try to make not jump on login - gKeyboard->resetKeys(); - } - - // when we get to this state, we've already been past the login UI - // (possiblely automatically) - flag this so we can test in the - // STATE_LOGIN_SHOW state if we've gone backwards - mLoginStatePastUI = true; - - // save the credentials - std::string userid = "unknown"; + return FALSE; + } + + if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) + { + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // Don't do anything. Wait for the login view to call the login_callback, + // which will push us to the next state. + + // display() function will be the one to run display_startup() + // Sleep so we don't spin the CPU + ms_sleep(1); + return FALSE; + } + + if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) + { + // Post login screen, we should see if any settings have changed that may + // require us to either start/stop or change the socks proxy. As various communications + // past this point may require the proxy to be up. + if (!LLStartUp::startLLProxy()) + { + // Proxy start up failed, we should now bail the state machine + // startLLProxy() will have reported an error to the user + // already, so we just go back to the login screen. The user + // could then change the preferences to fix the issue. + + LLStartUp::setStartupState(STATE_LOGIN_SHOW); + return FALSE; + } + + // reset the values that could have come in from a slurl + // DEV-42215: Make sure they're not empty -- gUserCredential + // might already have been set from gSavedSettings, and it's too bad + // to overwrite valid values with empty strings. + + if (show_connect_box) + { + // TODO if not use viewer auth + // Load all the name information out of the login view + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); + // end TODO + + // HACK: Try to make not jump on login + gKeyboard->resetKeys(); + } + + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // save the credentials + std::string userid = "unknown"; if (gUserCredential.notNull()) { userid = gUserCredential->userID(); @@ -928,24 +928,24 @@ bool idle_startup() gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); } } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); - gSavedSettings.setBOOL("RememberUser", gRememberUser); - LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; - gDebugInfo["LoginName"] = userid; - - // create necessary directories - // *FIX: these mkdir's should error check - gDirUtilp->setLindenUserDir(userid); - LLFile::mkdir(gDirUtilp->getLindenUserDir()); - - // As soon as directories are ready initialize notification storages - if (!LLPersistentNotificationStorage::instanceExists()) - { - // check existance since this part of code can be reached - // twice due to login failures - LLPersistentNotificationStorage::initParamSingleton(); - LLDoNotDisturbNotificationStorage::initParamSingleton(); - } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); + LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; + gDebugInfo["LoginName"] = userid; + + // create necessary directories + // *FIX: these mkdir's should error check + gDirUtilp->setLindenUserDir(userid); + LLFile::mkdir(gDirUtilp->getLindenUserDir()); + + // As soon as directories are ready initialize notification storages + if (!LLPersistentNotificationStorage::instanceExists()) + { + // check existance since this part of code can be reached + // twice due to login failures + LLPersistentNotificationStorage::initParamSingleton(); + LLDoNotDisturbNotificationStorage::initParamSingleton(); + } else { // reinitialize paths in case user switched grids or accounts @@ -953,152 +953,152 @@ bool idle_startup() LLDoNotDisturbNotificationStorage::getInstance()->reset(); } - // Set PerAccountSettingsFile to the default value. - std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); - gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); - gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; - - // Note: can't store warnings files per account because some come up before login - - // Overwrite default user settings with user settings - LLAppViewer::instance()->loadSettingsFromDirectory("Account"); - - // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). - LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); - if (logInstantMessagesControl.notNull()) - { - gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); - } - - // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation - // and startup time is close enough if we don't have a real value. - if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) - { - gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); - } - - //Default the path if one isn't set. - // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was - // provided in pre 2.0 viewer. See EXT-6661 - if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) - { - gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); - gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); - } - else - { - gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); - } - gDirUtilp->setPerAccountChatLogsDir(userid); - - LLFile::mkdir(gDirUtilp->getChatLogsDir()); - LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); - - if (show_connect_box) - { - LLSLURL slurl; - //LLPanelLogin::closePanel(); - } - - - // Load URL History File - LLURLHistory::loadFile("url_history.xml"); - // Load location history - LLLocationHistory::getInstance()->load(); - - // Load Avatars icons cache - LLAvatarIconIDCache::getInstance()->load(); - - LLRenderMuteList::getInstance()->loadFromFile(); - - //------------------------------------------------- - // Handle startup progress screen - //------------------------------------------------- - - // on startup the user can request to go to their home, - // their last location, or some URL "-url //sim/x/y[/z]" - // All accounts have both a home and a last location, and we don't support - // more locations than that. Choose the appropriate one. JC - switch (LLStartUp::getStartSLURL().getType()) - { - case LLSLURL::LOCATION: - agent_location_id = START_LOCATION_ID_URL; - break; - case LLSLURL::LAST_LOCATION: - agent_location_id = START_LOCATION_ID_LAST; - break; - default: - agent_location_id = START_LOCATION_ID_HOME; - break; - } - - gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - - // Display the startup progress bar. - gViewerWindow->initTextures(agent_location_id); - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); - - gViewerWindow->revealIntroPanel(); - - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); - - return FALSE; - } - - if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) - { - gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); - - // Update progress status and the display loop. - auth_desc = LLTrans::getString("LoginInProgress"); - set_startup_status(progress, auth_desc, auth_message); - progress += 0.02f; - display_startup(); - - // Setting initial values... - LLLoginInstance* login = LLLoginInstance::getInstance(); - login->setNotificationsInterface(LLNotifications::getInstance()); - - login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); - login->setLastExecEvent(gLastExecEvent); - login->setLastExecDuration(gLastExecDuration); - - // This call to LLLoginInstance::connect() starts the - // authentication process. - login->connect(gUserCredential); - - LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); - return FALSE; - } - - if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) - { - // If we get here we have gotten past the potential stall - // in curl, so take "may appear frozen" out of progress bar. JC - auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); - set_startup_status(progress, auth_desc, auth_message); - - LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); - return FALSE; - } - - if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) - { - // Generic failure message - std::ostringstream emsg; - emsg << LLTrans::getString("LoginFailedHeader") << "\n"; - if(LLLoginInstance::getInstance()->authFailure()) - { - LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " - << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; - LLSD response = LLLoginInstance::getInstance()->getResponse(); - // Still have error conditions that may need some - // sort of handling - dig up specific message - std::string reason_response = response["reason"]; - std::string message_response = response["message"]; - std::string message_id = response["message_id"]; - std::string message; // actual string to show the user + // Set PerAccountSettingsFile to the default value. + std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); + gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); + gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; + + // Note: can't store warnings files per account because some come up before login + + // Overwrite default user settings with user settings + LLAppViewer::instance()->loadSettingsFromDirectory("Account"); + + // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). + LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); + if (logInstantMessagesControl.notNull()) + { + gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); + } + + // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation + // and startup time is close enough if we don't have a real value. + if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) + { + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + } + + //Default the path if one isn't set. + // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was + // provided in pre 2.0 viewer. See EXT-6661 + if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) + { + gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); + gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); + } + else + { + gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + } + gDirUtilp->setPerAccountChatLogsDir(userid); + + LLFile::mkdir(gDirUtilp->getChatLogsDir()); + LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); + + if (show_connect_box) + { + LLSLURL slurl; + //LLPanelLogin::closePanel(); + } + + + // Load URL History File + LLURLHistory::loadFile("url_history.xml"); + // Load location history + LLLocationHistory::getInstance()->load(); + + // Load Avatars icons cache + LLAvatarIconIDCache::getInstance()->load(); + + LLRenderMuteList::getInstance()->loadFromFile(); + + //------------------------------------------------- + // Handle startup progress screen + //------------------------------------------------- + + // on startup the user can request to go to their home, + // their last location, or some URL "-url //sim/x/y[/z]" + // All accounts have both a home and a last location, and we don't support + // more locations than that. Choose the appropriate one. JC + switch (LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + agent_location_id = START_LOCATION_ID_URL; + break; + case LLSLURL::LAST_LOCATION: + agent_location_id = START_LOCATION_ID_LAST; + break; + default: + agent_location_id = START_LOCATION_ID_HOME; + break; + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + // Display the startup progress bar. + gViewerWindow->initTextures(agent_location_id); + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); + + gViewerWindow->revealIntroPanel(); + + LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); + + return FALSE; + } + + if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) + { + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); + + // Update progress status and the display loop. + auth_desc = LLTrans::getString("LoginInProgress"); + set_startup_status(progress, auth_desc, auth_message); + progress += 0.02f; + display_startup(); + + // Setting initial values... + LLLoginInstance* login = LLLoginInstance::getInstance(); + login->setNotificationsInterface(LLNotifications::getInstance()); + + login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); + login->setLastExecEvent(gLastExecEvent); + login->setLastExecDuration(gLastExecDuration); + + // This call to LLLoginInstance::connect() starts the + // authentication process. + login->connect(gUserCredential); + + LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); + return FALSE; + } + + if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) + { + // If we get here we have gotten past the potential stall + // in curl, so take "may appear frozen" out of progress bar. JC + auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); + set_startup_status(progress, auth_desc, auth_message); + + LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); + return FALSE; + } + + if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) + { + // Generic failure message + std::ostringstream emsg; + emsg << LLTrans::getString("LoginFailedHeader") << "\n"; + if(LLLoginInstance::getInstance()->authFailure()) + { + LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " + << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; + LLSD response = LLLoginInstance::getInstance()->getResponse(); + // Still have error conditions that may need some + // sort of handling - dig up specific message + std::string reason_response = response["reason"]; + std::string message_response = response["message"]; + std::string message_id = response["message_id"]; + std::string message; // actual string to show the user bool localized_by_id = false; if(!message_id.empty()) @@ -1131,63 +1131,63 @@ bool idle_startup() } if(!localized_by_id && !message_response.empty()) - { - // *HACK: "no_inventory_host" sent as the message itself. - // Remove this clause when server is sending message_id as well. - message = LLAgent::sTeleportErrorMessages[ message_response ]; - } - - if (message.empty()) - { - // Fallback to server-supplied string; necessary since server - // may add strings that this viewer is not yet aware of - message = message_response; - } - - emsg << message; - - - if(reason_response == "key") - { - // Couldn't login because user/password is wrong - // Clear the credential - gUserCredential->clearAuthenticator(); - } - - if(reason_response == "update" - || reason_response == "optional") - { - // In the case of a needed update, quit. - // Its either downloading or declined. - // If optional was skipped this case shouldn't - // be reached. - - LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; - LLLoginInstance::getInstance()->disconnect(); - LLAppViewer::instance()->forceQuit(); - } - else - { - if (reason_response != "tos" && reason_response != "mfa_challenge") - { - // Don't pop up a notification in the TOS or MFA cases because - // the specialized floater has already scolded the user. - std::string error_code; - if(response.has("errorcode")) - { - error_code = response["errorcode"].asString(); - } - if ((reason_response == "CURLError") && - (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && - response.has("certificate")) - { - // This was a certificate error, so grab the certificate - // and throw up the appropriate dialog. - LLPointer certificate; - try - { - certificate = gSecAPIHandler->getCertificate(response["certificate"]); - } + { + // *HACK: "no_inventory_host" sent as the message itself. + // Remove this clause when server is sending message_id as well. + message = LLAgent::sTeleportErrorMessages[ message_response ]; + } + + if (message.empty()) + { + // Fallback to server-supplied string; necessary since server + // may add strings that this viewer is not yet aware of + message = message_response; + } + + emsg << message; + + + if(reason_response == "key") + { + // Couldn't login because user/password is wrong + // Clear the credential + gUserCredential->clearAuthenticator(); + } + + if(reason_response == "update" + || reason_response == "optional") + { + // In the case of a needed update, quit. + // Its either downloading or declined. + // If optional was skipped this case shouldn't + // be reached. + + LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL; + LLLoginInstance::getInstance()->disconnect(); + LLAppViewer::instance()->forceQuit(); + } + else + { + if (reason_response != "tos" && reason_response != "mfa_challenge") + { + // Don't pop up a notification in the TOS or MFA cases because + // the specialized floater has already scolded the user. + std::string error_code; + if(response.has("errorcode")) + { + error_code = response["errorcode"].asString(); + } + if ((reason_response == "CURLError") && + (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && + response.has("certificate")) + { + // This was a certificate error, so grab the certificate + // and throw up the appropriate dialog. + LLPointer certificate; + try + { + certificate = gSecAPIHandler->getCertificate(response["certificate"]); + } catch (LLCertException &cert_exception) { LL_WARNS("LLStartup", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL; @@ -1201,1231 +1201,1231 @@ bool idle_startup() gSavedSettings.setBOOL("AutoLogin", FALSE); show_connect_box = true; } - if(certificate) - { - LLSD args = transform_cert_args(certificate); - - if(error_code == "SSL_CACERT") - { - // if we are handling an untrusted CA, throw up the dialog - // with the 'trust this CA' button. - LLNotificationsUtil::add("TrustCertificateError", args, response, - trust_cert_done); - - show_connect_box = true; - } - else - { - // the certificate exception returns a unique string for each type of exception. - // we grab this string via the LLUserAuth object, and use that to grab the localized - // string. - args["REASON"] = LLTrans::getString(message_response); - - LLNotificationsUtil::add("GeneralCertificateError", args, response, - general_cert_done); - - reset_login(); - gSavedSettings.setBOOL("AutoLogin", FALSE); - show_connect_box = true; - - } - - } - } + if(certificate) + { + LLSD args = transform_cert_args(certificate); + + if(error_code == "SSL_CACERT") + { + // if we are handling an untrusted CA, throw up the dialog + // with the 'trust this CA' button. + LLNotificationsUtil::add("TrustCertificateError", args, response, + trust_cert_done); + + show_connect_box = true; + } + else + { + // the certificate exception returns a unique string for each type of exception. + // we grab this string via the LLUserAuth object, and use that to grab the localized + // string. + args["REASON"] = LLTrans::getString(message_response); + + LLNotificationsUtil::add("GeneralCertificateError", args, response, + general_cert_done); + + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + show_connect_box = true; + + } + + } + } else if (reason_response == "BadType") { LLNotificationsUtil::add("LoginFailedToParse", LLSD(), LLSD(), login_alert_done); } - else if (!message.empty()) - { - // This wasn't a certificate error, so throw up the normal - // notificatioin message. - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); - } - } - transition_back_to_login_panel(emsg.str()); - show_connect_box = true; - } - } - else if(LLLoginInstance::getInstance()->authSuccess()) - { - if(process_login_success_response()) - { - // Pass the user information to the voice chat server interface. - LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); - // create the default proximal channel - LLVoiceChannel::initClass(); - LLStartUp::setStartupState( STATE_WORLD_INIT); - LLTrace::get_frame_recording().reset(); - } - else - { - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); - transition_back_to_login_panel(emsg.str()); - show_connect_box = true; - return FALSE; - } - } - return FALSE; - } - - //--------------------------------------------------------------------- - // World Init - //--------------------------------------------------------------------- - if (STATE_WORLD_INIT == LLStartUp::getStartupState()) - { - set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); - display_startup(); - // We should have an agent id by this point. - llassert(!(gAgentID == LLUUID::null)); - - // Finish agent initialization. (Requires gSavedSettings, builds camera) - gAgent.init(); - display_startup(); - gAgentCamera.init(); - display_startup(); - display_startup(); - - // Since we connected, save off the settings so the user doesn't have to - // type the name/password again if we crash. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - LLUIColorTable::instance().saveUserSettings(); - - display_startup(); - - // - // Initialize classes w/graphics stuff. - // - LLViewerStatsRecorder::instance(); // Since textures work in threads - LLSurface::initClasses(); - display_startup(); - - display_startup(); - - LLDrawable::initClass(); - display_startup(); - - // init the shader managers - LLPostProcess::initClass(); - display_startup(); + else if (!message.empty()) + { + // This wasn't a certificate error, so throw up the normal + // notificatioin message. + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + } + } + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + } + } + else if(LLLoginInstance::getInstance()->authSuccess()) + { + if(process_login_success_response()) + { + // Pass the user information to the voice chat server interface. + LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); + // create the default proximal channel + LLVoiceChannel::initClass(); + LLStartUp::setStartupState( STATE_WORLD_INIT); + LLTrace::get_frame_recording().reset(); + } + else + { + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + return FALSE; + } + } + return FALSE; + } + + //--------------------------------------------------------------------- + // World Init + //--------------------------------------------------------------------- + if (STATE_WORLD_INIT == LLStartUp::getStartupState()) + { + set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + display_startup(); + // We should have an agent id by this point. + llassert(!(gAgentID == LLUUID::null)); + + // Finish agent initialization. (Requires gSavedSettings, builds camera) + gAgent.init(); + display_startup(); + gAgentCamera.init(); + display_startup(); + display_startup(); + + // Since we connected, save off the settings so the user doesn't have to + // type the name/password again if we crash. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + LLUIColorTable::instance().saveUserSettings(); + + display_startup(); + + // + // Initialize classes w/graphics stuff. + // + LLViewerStatsRecorder::instance(); // Since textures work in threads + LLSurface::initClasses(); + display_startup(); + + display_startup(); + + LLDrawable::initClass(); + display_startup(); + + // init the shader managers + LLPostProcess::initClass(); + display_startup(); + + LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); + display_startup(); + + LLViewerObject::initVOClasses(); + display_startup(); + + // Initialize all our tools. Must be done after saved settings loaded. + // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. + LLToolMgr::getInstance()->initTools(); + display_startup(); + + // Pre-load floaters, like the world map, that are slow to spawn + // due to XML complexity. + gViewerWindow->initWorldUI(); + + display_startup(); + + // This is where we used to initialize gWorldp. Original comment said: + // World initialization must be done after above window init + + // User might have overridden far clip + LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); + display_startup(); + // Before we create the first region, we need to set the agent's mOriginGlobal + // This is necessary because creating objects before this is set will result in a + // bad mPositionAgent cache. + + gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); + display_startup(); + + LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); + display_startup(); + + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " + << gFirstSimSeedCap << LL_ENDL; + regionp->setSeedCapability(gFirstSimSeedCap); + LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; + display_startup(); + // Set agent's initial region to be the one we just created. + gAgent.setRegion(regionp); + display_startup(); + // Set agent's initial position, which will be read by LLVOAvatar when the avatar + // object is created. I think this must be done after setting the region. JC + gAgent.setPositionAgent(agent_start_position_region); + + display_startup(); + LLStartUp::initExperiences(); + + display_startup(); + + // If logging should be enebled, turns it on and loads history from disk + // Note: does not happen on init of singleton because preferences can use + // this instance without logging in + LLConversationLog::getInstance()->initLoggingState(); + + LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); + + return FALSE; + } + + + //--------------------------------------------------------------------- + // Load QuickTime/GStreamer and other multimedia engines, can be slow. + // Do it while we're waiting on the network for our seed capability. JC + //--------------------------------------------------------------------- + if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) + { + LLStartUp::multimediaInit(); + LLStartUp::setStartupState( STATE_FONT_INIT ); + display_startup(); + return FALSE; + } + + // Loading fonts takes several seconds + if (STATE_FONT_INIT == LLStartUp::getStartupState()) + { + LLStartUp::fontInit(); + LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); + display_startup(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Wait for Seed Cap Grant + //--------------------------------------------------------------------- + if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + if (regionp->capabilitiesReceived()) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + else if (regionp->capabilitiesError()) + { + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else + { + U32 num_retries = regionp->getNumSeedCapRetries(); + if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) + { + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else if (num_retries > 0) + { + LLStringUtil::format_map_t args; + args["[NUMBER]"] = llformat("%d", num_retries + 1); + set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); + } + else + { + set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); + } + } + display_startup(); + return FALSE; + } + + + //--------------------------------------------------------------------- + // Seed Capability Granted + // no newMessage calls should happen before this point + //--------------------------------------------------------------------- + if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) + { + display_startup(); + + // These textures are not warrantied to be cached, so needs + // to hapen with caps granted + gTextureList.doPrefetchImages(); + + // will init images, should be done with caps, but before gSky.init() + LLEnvironment::getInstance()->initSingleton(); + + display_startup(); + update_texture_fetch(); + display_startup(); + + if ( gViewerWindow != NULL) + { // This isn't the first logon attempt, so show the UI + gViewerWindow->setNormalControlsVisible( TRUE ); + } + gLoginMenuBarView->setVisible( FALSE ); + gLoginMenuBarView->setEnabled( FALSE ); + display_startup(); + + // direct logging to the debug console's line buffer + LLError::logToFixedBuffer(gDebugView->mDebugConsolep); + display_startup(); + + // set initial visibility of debug console + gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); + display_startup(); + + // + // Set message handlers + // + LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; + + // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted + register_viewer_callbacks(gMessageSystem); + display_startup(); + + // Debugging info parameters + gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms + display_startup(); + + #ifndef LL_RELEASE_FOR_DOWNLOAD + gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg + gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode + #endif + display_startup(); + + gXferManager->registerCallbacks(gMessageSystem); + display_startup(); + + LLStartUp::initNameCache(); + display_startup(); + + // update the voice settings *after* gCacheName initialization + // so that we can construct voice UI that relies on the name cache + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->updateSettings(); + } + display_startup(); + + // create a container's instance for start a controlling conversation windows + // by the voice's events + LLFloaterIMContainer::getInstance(); + if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) + { + LLViewerParcelAskPlay::getInstance()->loadSettings(); + } + + gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); + + // *Note: this is where gWorldMap used to be initialized. + + // register null callbacks for audio until the audio system is initialized + gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); + gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); + display_startup(); + + //reset statistics + LLViewerStats::instance().resetStats(); + + display_startup(); + // + // Set up region and surface defaults + // + + + // Sets up the parameters for the first simulator + + LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; + gFrameTime = totalTime(); + F32Seconds last_time = gFrameTimeSeconds; + gFrameTimeSeconds = (gFrameTime - gStartTime); + + gFrameIntervalSeconds = gFrameTimeSeconds - last_time; + if (gFrameIntervalSeconds < 0.f) + { + gFrameIntervalSeconds = 0.f; + } + + // Make sure agent knows correct aspect ratio + // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below + LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); + LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); + // Initialize FOV + LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); + display_startup(); + + // Move agent to starting location. The position handed to us by + // the space server is in global coordinates, but the agent frame + // is in region local coordinates. Therefore, we need to adjust + // the coordinates handed to us to fit in the local region. + + gAgent.setPositionAgent(agent_start_position_region); + gAgent.resetAxes(gAgentStartLookAt); + gAgentCamera.stopCameraAnimation(); + gAgentCamera.resetCamera(); + display_startup(); + + // Initialize global class data needed for surfaces (i.e. textures) + LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; + // Initialize all of the viewer object classes for the first time (doing things like texture fetches. + LLGLState::checkStates(); + + gSky.init(); + + LLGLState::checkStates(); + + display_startup(); + + LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; + // For all images pre-loaded into viewer cache, init + // priorities and fetching using decodeAllImages. + // Most of the fetching and decoding likely to be done + // by update_texture_fetch() later, while viewer waits. + // + // Need to do this AFTER we init the sky + const S32 DECODE_TIME_SEC = 2; + for (int i = 0; i < DECODE_TIME_SEC; i++) + { + F32 frac = (F32)i / (F32)DECODE_TIME_SEC; + set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); + display_startup(); + gTextureList.decodeAllImages(1.f); + } + LLStartUp::setStartupState( STATE_WORLD_WAIT ); + + display_startup(); + + // JC - Do this as late as possible to increase likelihood Purify + // will run. + LLMessageSystem* msg = gMessageSystem; + if (!msg->mOurCircuitCode) + { + LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; + } + + gUseCircuitCallbackCalled = false; + + msg->enableCircuit(gFirstSim, TRUE); + // now, use the circuit info to tell simulator about us! + LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; + msg->newMessageFast(_PREHASH_UseCircuitCode); + msg->nextBlockFast(_PREHASH_CircuitCode); + msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); + msg->sendReliable( + gFirstSim, + gSavedSettings.getS32("UseCircuitCodeMaxRetries"), + FALSE, + (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), + use_circuit_callback, + NULL); + + timeout.reset(); + display_startup(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // World Wait + //--------------------------------------------------------------------- + if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; + set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); + if(gGotUseCircuitCodeAck) + { + LLStartUp::setStartupState( STATE_AGENT_SEND ); + } + pump_idle_startup_network(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Send + //--------------------------------------------------------------------- + if (STATE_AGENT_SEND == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; + set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); + display_startup(); + // register with the message system so it knows we're + // expecting this message + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast( + _PREHASH_AgentMovementComplete, + process_agent_movement_complete); + LLViewerRegion* regionp = gAgent.getRegion(); + if(regionp) + { + send_complete_agent_movement(regionp->getHost()); + gAssetStorage->setUpstream(regionp->getHost()); + gCacheName->setUpstream(regionp->getHost()); + } + display_startup(); + + // Create login effect + // But not on first login, because you can't see your avatar then + if (!gAgent.isFirstLogin()) + { + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + } + + LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT + + timeout.reset(); + display_startup(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Wait + //--------------------------------------------------------------------- + if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) + { + { + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) + { + if (gAgentMovementCompleted) + { + // Sometimes we have more than one message in the + // queue. break out of this loop and continue + // processing. If we don't, then this could skip one + // or more login steps. + break; + } + else + { + LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " + << gMessageSystem->getMessageName() << LL_ENDL; + } + display_startup(); + } + lmc.processAcks(); + } + + display_startup(); + + if (gAgentMovementCompleted) + { + LLStartUp::setStartupState( STATE_INVENTORY_SEND ); + } + display_startup(); + + if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) + { + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + return FALSE; + } + + //--------------------------------------------------------------------- + // Inventory Send + //--------------------------------------------------------------------- + if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory send") + display_startup(); + + // request mute list + LL_INFOS() << "Requesting Mute List" << LL_ENDL; + LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + + // Get L$ and ownership credit information + LL_INFOS() << "Requesting Money Balance" << LL_ENDL; + LLStatusBar::sendMoneyBalanceRequest(); + + display_startup(); + + // Inform simulator of our language preference + LLAgentLanguage::update(); + + display_startup(); + // unpack thin inventory + LLSD response = LLLoginInstance::getInstance()->getResponse(); + //bool dump_buffer = false; + + LLSD inv_lib_root = response["inventory-lib-root"]; + if(inv_lib_root.isDefined()) + { + // should only be one + LLSD id = inv_lib_root[0]["folder_id"]; + if(id.isDefined()) + { + gInventory.setLibraryRootFolderID(id.asUUID()); + } + } + display_startup(); + + LLSD inv_lib_owner = response["inventory-lib-owner"]; + if(inv_lib_owner.isDefined()) + { + // should only be one + LLSD id = inv_lib_owner[0]["agent_id"]; + if(id.isDefined()) + { + gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); + } + } + display_startup(); + LLStartUp::setStartupState(STATE_INVENTORY_SKEL); + display_startup(); + return FALSE; + } + + if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory load skeleton") + + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + LLSD inv_skel_lib = response["inventory-skel-lib"]; + if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + { + LL_PROFILE_ZONE_NAMED("load library inv") + if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + } + } + display_startup(); + + LLSD inv_skeleton = response["inventory-skeleton"]; + if (inv_skeleton.isDefined()) + { + LL_PROFILE_ZONE_NAMED("load personal inv") + if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; + } + } + display_startup(); + LLStartUp::setStartupState(STATE_INVENTORY_SEND2); + display_startup(); + return FALSE; + } + + if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState()) + { + LL_PROFILE_ZONE_NAMED("State inventory send2") + + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + LLSD inv_basic = response["inventory-basic"]; + if(inv_basic.isDefined()) + { + LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; + } + + LLSD buddy_list = response["buddy-list"]; + if(buddy_list.isDefined()) + { + LLAvatarTracker::buddy_map_t list; + LLUUID agent_id; + S32 has_rights = 0, given_rights = 0; + for(LLSD::array_const_iterator it = buddy_list.beginArray(), + end = buddy_list.endArray(); it != end; ++it) + { + LLSD buddy_id = (*it)["buddy_id"]; + if(buddy_id.isDefined()) + { + agent_id = buddy_id.asUUID(); + } + + LLSD buddy_rights_has = (*it)["buddy_rights_has"]; + if(buddy_rights_has.isDefined()) + { + has_rights = buddy_rights_has.asInteger(); + } + + LLSD buddy_rights_given = (*it)["buddy_rights_given"]; + if(buddy_rights_given.isDefined()) + { + given_rights = buddy_rights_given.asInteger(); + } + + list[agent_id] = new LLRelationship(given_rights, has_rights, false); + } + LLAvatarTracker::instance().addBuddyList(list); + display_startup(); + } + + bool show_hud = false; + LLSD tutorial_setting = response["tutorial_setting"]; + if(tutorial_setting.isDefined()) + { + for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), + end = tutorial_setting.endArray(); it != end; ++it) + { + LLSD tutorial_url = (*it)["tutorial_url"]; + if(tutorial_url.isDefined()) + { + // Tutorial floater will append language code + gSavedSettings.setString("TutorialURL", tutorial_url.asString()); + } + + // For Viewer 2.0 we are not using the web-based tutorial + // If we reverse that decision, put this code back and use + // login.cgi to send a different URL with content that matches + // the Viewer 2.0 UI. + //LLSD use_tutorial = (*it)["use_tutorial"]; + //if(use_tutorial.asString() == "true") + //{ + // show_hud = true; + //} + } + } + display_startup(); + + // Either we want to show tutorial because this is the first login + // to a Linden Help Island or the user quit with the tutorial + // visible. JC + if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) + { + LLFloaterReg::showInstance("hud", LLSD(), FALSE); + } + display_startup(); + + LLSD event_notifications = response["event_notifications"]; + if(event_notifications.isDefined()) + { + gEventNotifier.load(event_notifications); + } + display_startup(); + + LLSD classified_categories = response["classified_categories"]; + if(classified_categories.isDefined()) + { + LLClassifiedInfo::loadCategories(classified_categories); + } + display_startup(); + + // This method MUST be called before gInventory.findCategoryUUIDForType because of + // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. + gInventory.buildParentChildMap(); + + // If buildParentChildMap succeeded, inventory will now be in + // a usable state and gInventory.isInventoryUsable() will be + // true. + + // if inventory is unusable, show warning. + if (!gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("InventoryUnusable"); + } + + LLInventoryModelBackgroundFetch::instance().start(); + gInventory.createCommonSystemCategories(); + LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); + display_startup(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // STATE_INVENTORY_CALLBACKS + //--------------------------------------------------------------------- + if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) + { + if (!LLInventoryModel::isSysFoldersReady()) + { + display_startup(); + return FALSE; + } + LLInventoryModelBackgroundFetch::instance().start(); + LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); + if (cof + && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // Special case, dupplicate request prevention. + // Cof folder will be requested via FetchCOF + // in appearance manager, prevent recursive fetch + cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); + } + + + // It's debatable whether this flag is a good idea - sets all + // bits, and in general it isn't true that inventory + // initialization generates all types of changes. Maybe add an + // INITIALIZE mask bit instead? + gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); + gInventory.notifyObservers(); + + display_startup(); + + // set up callbacks + LL_INFOS() << "Registering Callbacks" << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + LL_INFOS() << " Inventory" << LL_ENDL; + LLInventoryModel::registerCallbacks(msg); + LL_INFOS() << " AvatarTracker" << LL_ENDL; + LLAvatarTracker::instance().registerCallbacks(msg); + LL_INFOS() << " Landmark" << LL_ENDL; + LLLandmark::registerCallbacks(msg); + display_startup(); + + // request all group information + LL_INFOS() << "Requesting Agent Data" << LL_ENDL; + gAgent.sendAgentDataUpdateRequest(); + display_startup(); + // Create the inventory views + LL_INFOS() << "Creating Inventory Views" << LL_ENDL; + LLFloaterReg::getInstance("inventory"); + display_startup(); + LLStartUp::setStartupState( STATE_MISC ); + display_startup(); + + return FALSE; + } + - LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); - display_startup(); - - LLViewerObject::initVOClasses(); - display_startup(); - - // Initialize all our tools. Must be done after saved settings loaded. - // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. - LLToolMgr::getInstance()->initTools(); - display_startup(); - - // Pre-load floaters, like the world map, that are slow to spawn - // due to XML complexity. - gViewerWindow->initWorldUI(); - - display_startup(); - - // This is where we used to initialize gWorldp. Original comment said: - // World initialization must be done after above window init - - // User might have overridden far clip - LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); - display_startup(); - // Before we create the first region, we need to set the agent's mOriginGlobal - // This is necessary because creating objects before this is set will result in a - // bad mPositionAgent cache. - - gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); - display_startup(); - - LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); - display_startup(); - - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); - LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; - - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " - << gFirstSimSeedCap << LL_ENDL; - regionp->setSeedCapability(gFirstSimSeedCap); - LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; - display_startup(); - // Set agent's initial region to be the one we just created. - gAgent.setRegion(regionp); - display_startup(); - // Set agent's initial position, which will be read by LLVOAvatar when the avatar - // object is created. I think this must be done after setting the region. JC - gAgent.setPositionAgent(agent_start_position_region); - - display_startup(); - LLStartUp::initExperiences(); - - display_startup(); - - // If logging should be enebled, turns it on and loads history from disk - // Note: does not happen on init of singleton because preferences can use - // this instance without logging in - LLConversationLog::getInstance()->initLoggingState(); - - LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); - - return FALSE; - } - - - //--------------------------------------------------------------------- - // Load QuickTime/GStreamer and other multimedia engines, can be slow. - // Do it while we're waiting on the network for our seed capability. JC - //--------------------------------------------------------------------- - if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) - { - LLStartUp::multimediaInit(); - LLStartUp::setStartupState( STATE_FONT_INIT ); - display_startup(); - return FALSE; - } - - // Loading fonts takes several seconds - if (STATE_FONT_INIT == LLStartUp::getStartupState()) - { - LLStartUp::fontInit(); - LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); - display_startup(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Wait for Seed Cap Grant - //--------------------------------------------------------------------- - if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); - if (regionp->capabilitiesReceived()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - else if (regionp->capabilitiesError()) + //--------------------------------------------------------------------- + // Misc + //--------------------------------------------------------------------- + if (STATE_MISC == LLStartUp::getStartupState()) + { + // We have a region, and just did a big inventory download. + // We can estimate the user's connection speed, and set their + // max bandwidth accordingly. JC + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { - LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) + // This is actually a pessimistic computation, because TCP may not have enough + // time to ramp up on the (small) default inventory file to truly measure max + // bandwidth. JC + F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); + const F32 FAST_RATE_BPS = 600.f * 1024.f; + const F32 FASTER_RATE_BPS = 750.f * 1024.f; + F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); + if (rate_bps > FASTER_RATE_BPS + && rate_bps > max_bandwidth) { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FASTER_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); } - else + else if (rate_bps > FAST_RATE_BPS + && rate_bps > max_bandwidth) { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FAST_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); } - reset_login(); - } - else - { - U32 num_retries = regionp->getNumSeedCapRetries(); - if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) + + if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) { - LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); + gSavedSettings.setBOOL("HelpFloaterOpen", TRUE); } - else if (num_retries > 0) - { - LLStringUtil::format_map_t args; - args["[NUMBER]"] = llformat("%d", num_retries + 1); - set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); - } - else - { - set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); - } - } - display_startup(); - return FALSE; - } - - - //--------------------------------------------------------------------- - // Seed Capability Granted - // no newMessage calls should happen before this point - //--------------------------------------------------------------------- - if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) - { - display_startup(); - // These textures are not warrantied to be cached, so needs - // to hapen with caps granted - gTextureList.doPrefetchImages(); - - // will init images, should be done with caps, but before gSky.init() - LLEnvironment::getInstance()->initSingleton(); + // Set the show start location to true, now that the user has logged + // on with this install. + gSavedSettings.setBOOL("ShowStartLocation", TRUE); + } display_startup(); - update_texture_fetch(); - display_startup(); - - if ( gViewerWindow != NULL) - { // This isn't the first logon attempt, so show the UI - gViewerWindow->setNormalControlsVisible( TRUE ); - } - gLoginMenuBarView->setVisible( FALSE ); - gLoginMenuBarView->setEnabled( FALSE ); - display_startup(); - - // direct logging to the debug console's line buffer - LLError::logToFixedBuffer(gDebugView->mDebugConsolep); - display_startup(); - - // set initial visibility of debug console - gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); - display_startup(); - - // - // Set message handlers - // - LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; - - // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted - register_viewer_callbacks(gMessageSystem); - display_startup(); - - // Debugging info parameters - gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms - display_startup(); - - #ifndef LL_RELEASE_FOR_DOWNLOAD - gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg - gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode - #endif - display_startup(); - - gXferManager->registerCallbacks(gMessageSystem); - display_startup(); - - LLStartUp::initNameCache(); - display_startup(); - - // update the voice settings *after* gCacheName initialization - // so that we can construct voice UI that relies on the name cache - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->updateSettings(); - } - display_startup(); - - // create a container's instance for start a controlling conversation windows - // by the voice's events - LLFloaterIMContainer::getInstance(); - if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) - { - LLViewerParcelAskPlay::getInstance()->loadSettings(); - } - - gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); - - // *Note: this is where gWorldMap used to be initialized. - - // register null callbacks for audio until the audio system is initialized - gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); - gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); - display_startup(); - - //reset statistics - LLViewerStats::instance().resetStats(); - - display_startup(); - // - // Set up region and surface defaults - // - - - // Sets up the parameters for the first simulator - - LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; - gFrameTime = totalTime(); - F32Seconds last_time = gFrameTimeSeconds; - gFrameTimeSeconds = (gFrameTime - gStartTime); - - gFrameIntervalSeconds = gFrameTimeSeconds - last_time; - if (gFrameIntervalSeconds < 0.f) - { - gFrameIntervalSeconds = 0.f; - } - - // Make sure agent knows correct aspect ratio - // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below - LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); - LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); - // Initialize FOV - LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); - display_startup(); - - // Move agent to starting location. The position handed to us by - // the space server is in global coordinates, but the agent frame - // is in region local coordinates. Therefore, we need to adjust - // the coordinates handed to us to fit in the local region. - - gAgent.setPositionAgent(agent_start_position_region); - gAgent.resetAxes(gAgentStartLookAt); - gAgentCamera.stopCameraAnimation(); - gAgentCamera.resetCamera(); - display_startup(); - - // Initialize global class data needed for surfaces (i.e. textures) - LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; - // Initialize all of the viewer object classes for the first time (doing things like texture fetches. - LLGLState::checkStates(); - - gSky.init(); - - LLGLState::checkStates(); - - display_startup(); - - LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; - // For all images pre-loaded into viewer cache, init - // priorities and fetching using decodeAllImages. - // Most of the fetching and decoding likely to be done - // by update_texture_fetch() later, while viewer waits. - // - // Need to do this AFTER we init the sky - const S32 DECODE_TIME_SEC = 2; - for (int i = 0; i < DECODE_TIME_SEC; i++) - { - F32 frac = (F32)i / (F32)DECODE_TIME_SEC; - set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); - display_startup(); - gTextureList.decodeAllImages(1.f); - } - LLStartUp::setStartupState( STATE_WORLD_WAIT ); - - display_startup(); - - // JC - Do this as late as possible to increase likelihood Purify - // will run. - LLMessageSystem* msg = gMessageSystem; - if (!msg->mOurCircuitCode) - { - LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; - } - - gUseCircuitCallbackCalled = false; - - msg->enableCircuit(gFirstSim, TRUE); - // now, use the circuit info to tell simulator about us! - LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable( - gFirstSim, - gSavedSettings.getS32("UseCircuitCodeMaxRetries"), - FALSE, - (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), - use_circuit_callback, - NULL); - - timeout.reset(); - display_startup(); - - return FALSE; - } - - //--------------------------------------------------------------------- - // World Wait - //--------------------------------------------------------------------- - if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; - set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); - if(gGotUseCircuitCodeAck) - { - LLStartUp::setStartupState( STATE_AGENT_SEND ); - } - pump_idle_startup_network(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Agent Send - //--------------------------------------------------------------------- - if (STATE_AGENT_SEND == LLStartUp::getStartupState()) - { - LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; - set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); - display_startup(); - // register with the message system so it knows we're - // expecting this message - LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFuncFast( - _PREHASH_AgentMovementComplete, - process_agent_movement_complete); - LLViewerRegion* regionp = gAgent.getRegion(); - if(regionp) - { - send_complete_agent_movement(regionp->getHost()); - gAssetStorage->setUpstream(regionp->getHost()); - gCacheName->setUpstream(regionp->getHost()); - } - display_startup(); - - // Create login effect - // But not on first login, because you can't see your avatar then - if (!gAgent.isFirstLogin()) - { - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - } - - LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT - - timeout.reset(); - display_startup(); - return FALSE; - } - - //--------------------------------------------------------------------- - // Agent Wait - //--------------------------------------------------------------------- - if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) - { - { - LockMessageChecker lmc(gMessageSystem); - while (lmc.checkAllMessages(gFrameCount, gServicePump)) - { - if (gAgentMovementCompleted) - { - // Sometimes we have more than one message in the - // queue. break out of this loop and continue - // processing. If we don't, then this could skip one - // or more login steps. - break; - } - else - { - LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " - << gMessageSystem->getMessageName() << LL_ENDL; - } - display_startup(); - } - lmc.processAcks(); - } - - display_startup(); - - if (gAgentMovementCompleted) - { - LLStartUp::setStartupState( STATE_INVENTORY_SEND ); - } - display_startup(); - - if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) - { - LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); - } - return FALSE; - } - - //--------------------------------------------------------------------- - // Inventory Send - //--------------------------------------------------------------------- - if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) - { - LL_PROFILE_ZONE_NAMED("State inventory send") - display_startup(); - // request mute list - LL_INFOS() << "Requesting Mute List" << LL_ENDL; - LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + // Load stored local environment if needed. + LLEnvironment::instance().loadFromSettings(); - // Get L$ and ownership credit information - LL_INFOS() << "Requesting Money Balance" << LL_ENDL; - LLStatusBar::sendMoneyBalanceRequest(); + // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) + //check_merchant_status(); display_startup(); - // Inform simulator of our language preference - LLAgentLanguage::update(); - - display_startup(); - // unpack thin inventory - LLSD response = LLLoginInstance::getInstance()->getResponse(); - //bool dump_buffer = false; - - LLSD inv_lib_root = response["inventory-lib-root"]; - if(inv_lib_root.isDefined()) - { - // should only be one - LLSD id = inv_lib_root[0]["folder_id"]; - if(id.isDefined()) - { - gInventory.setLibraryRootFolderID(id.asUUID()); - } - } - display_startup(); - - LLSD inv_lib_owner = response["inventory-lib-owner"]; - if(inv_lib_owner.isDefined()) - { - // should only be one - LLSD id = inv_lib_owner[0]["agent_id"]; - if(id.isDefined()) - { - gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); - } - } - display_startup(); - LLStartUp::setStartupState(STATE_INVENTORY_SKEL); - display_startup(); - return FALSE; - } + if (gSavedSettings.getBOOL("HelpFloaterOpen")) + { + // show default topic + LLViewerHelp::instance().showTopic(""); + } - if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) - { - LL_PROFILE_ZONE_NAMED("State inventory load skeleton") + display_startup(); - LLSD response = LLLoginInstance::getInstance()->getResponse(); + // We're successfully logged in. + gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); - LLSD inv_skel_lib = response["inventory-skel-lib"]; - if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + LLFloaterReg::showInitialVisibleInstances(); + + LLFloaterGridStatus::getInstance()->startGridStatusTimer(); + + display_startup(); + + display_startup(); + // JC: Initializing audio requests many sounds for download. + init_audio(); + display_startup(); + + // JC: Initialize "active" gestures. This may also trigger + // many gesture downloads, if this is the user's first + // time on this machine or -purge has been run. + LLSD gesture_options + = LLLoginInstance::getInstance()->getResponse("gestures"); + if (gesture_options.isDefined()) { - LL_PROFILE_ZONE_NAMED("load library inv") - if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() + << LL_ENDL; + uuid_vec_t item_ids; + for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), + end = gesture_options.endArray(); resp_it != end; ++resp_it) { - LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + // If the id is not specifed in the LLSD, + // the LLSD operator[]() will return a null LLUUID. + LLUUID item_id = (*resp_it)["item_id"]; + LLUUID asset_id = (*resp_it)["asset_id"]; + + if (item_id.notNull() && asset_id.notNull()) + { + // Could schedule and delay these for later. + const BOOL no_inform_server = FALSE; + const BOOL no_deactivate_similar = FALSE; + LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, + no_inform_server, + no_deactivate_similar); + // We need to fetch the inventory items for these gestures + // so we have the names to populate the UI. + item_ids.push_back(item_id); + } } + // no need to add gesture to inventory observer, it's already made in constructor + LLGestureMgr::instance().setFetchIDs(item_ids); + LLGestureMgr::instance().startFetch(); } + gDisplaySwapBuffers = TRUE; display_startup(); - LLSD inv_skeleton = response["inventory-skeleton"]; - if (inv_skeleton.isDefined()) + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); + msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); + + LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; + + LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; + gRenderStartTime.reset(); + gForegroundTime.reset(); + + // HACK: Inform simulator of window size. + // Do this here so it's less likely to race with RegisterNewAgent. + // TODO: Put this into RegisterNewAgent + // JC - 7/20/2002 + gViewerWindow->sendShapeToSim(); + + LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); + + // The reason we show the alert is because we want to + // reduce confusion for when you log in and your provided + // location is not your expected location. So, if this is + // your first login, then you do not have an expectation, + // thus, do not show this alert. + if (!gAgent.isFirstLogin()) { - LL_PROFILE_ZONE_NAMED("load personal inv") - if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; + LLSLURL start_slurl = LLStartUp::getStartSLURL(); + LL_DEBUGS("AppInit") << "start slurl "<getResponse(); - - LLSD inv_basic = response["inventory-basic"]; - if(inv_basic.isDefined()) - { - LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; - } - - LLSD buddy_list = response["buddy-list"]; - if(buddy_list.isDefined()) - { - LLAvatarTracker::buddy_map_t list; - LLUUID agent_id; - S32 has_rights = 0, given_rights = 0; - for(LLSD::array_const_iterator it = buddy_list.beginArray(), - end = buddy_list.endArray(); it != end; ++it) - { - LLSD buddy_id = (*it)["buddy_id"]; - if(buddy_id.isDefined()) - { - agent_id = buddy_id.asUUID(); - } - - LLSD buddy_rights_has = (*it)["buddy_rights_has"]; - if(buddy_rights_has.isDefined()) - { - has_rights = buddy_rights_has.asInteger(); - } - - LLSD buddy_rights_given = (*it)["buddy_rights_given"]; - if(buddy_rights_given.isDefined()) - { - given_rights = buddy_rights_given.asInteger(); - } - - list[agent_id] = new LLRelationship(given_rights, has_rights, false); - } - LLAvatarTracker::instance().addBuddyList(list); - display_startup(); - } - - bool show_hud = false; - LLSD tutorial_setting = response["tutorial_setting"]; - if(tutorial_setting.isDefined()) - { - for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), - end = tutorial_setting.endArray(); it != end; ++it) - { - LLSD tutorial_url = (*it)["tutorial_url"]; - if(tutorial_url.isDefined()) - { - // Tutorial floater will append language code - gSavedSettings.setString("TutorialURL", tutorial_url.asString()); - } - - // For Viewer 2.0 we are not using the web-based tutorial - // If we reverse that decision, put this code back and use - // login.cgi to send a different URL with content that matches - // the Viewer 2.0 UI. - //LLSD use_tutorial = (*it)["use_tutorial"]; - //if(use_tutorial.asString() == "true") - //{ - // show_hud = true; - //} - } - } - display_startup(); - - // Either we want to show tutorial because this is the first login - // to a Linden Help Island or the user quit with the tutorial - // visible. JC - if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) - { - LLFloaterReg::showInstance("hud", LLSD(), FALSE); - } - display_startup(); - - LLSD event_notifications = response["event_notifications"]; - if(event_notifications.isDefined()) - { - gEventNotifier.load(event_notifications); - } - display_startup(); - - LLSD classified_categories = response["classified_categories"]; - if(classified_categories.isDefined()) - { - LLClassifiedInfo::loadCategories(classified_categories); - } - display_startup(); - - // This method MUST be called before gInventory.findCategoryUUIDForType because of - // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. - gInventory.buildParentChildMap(); - - // If buildParentChildMap succeeded, inventory will now be in - // a usable state and gInventory.isInventoryUsable() will be - // true. - - // if inventory is unusable, show warning. - if (!gInventory.isInventoryUsable()) - { - LLNotificationsUtil::add("InventoryUnusable"); - } - - LLInventoryModelBackgroundFetch::instance().start(); - gInventory.createCommonSystemCategories(); - LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); display_startup(); - return FALSE; + // wait precache-delay and for agent's avatar or a lot longer. + if ((timeout_frac > 1.f) && isAgentAvatarValid()) + { + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else if (timeout_frac > 10.f) + { + // If we exceed the wait above while isAgentAvatarValid is + // not true yet, we will change startup state and + // eventually (once avatar does get created) wind up at + // the gender chooser. This should occur only in very + // unusual circumstances, so set the timeout fairly high + // to minimize mistaken hits here. + LL_WARNS() << "Wait for valid avatar state exceeded " + << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else + { + update_texture_fetch(); + set_startup_status(0.60f + 0.30f * timeout_frac, + LLTrans::getString("LoginPrecaching"), + gAgent.mMOTD.c_str()); + display_startup(); + } + + return TRUE; } - //--------------------------------------------------------------------- - // STATE_INVENTORY_CALLBACKS - //--------------------------------------------------------------------- - if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) + if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) { - if (!LLInventoryModel::isSysFoldersReady()) + static LLFrameTimer wearables_timer; + + const F32 wearables_time = wearables_timer.getElapsedTimeF32(); + static LLCachedControl max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); + + if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { - display_startup(); - return FALSE; + // No point in waiting for clothing, we don't even know + // what outfit we want. Pop up a gender chooser dialog to + // ask and proceed to draw the world. JC + // + // *NOTE: We might hit this case even if we have an + // initial outfit, but if the load hasn't started + // already then something is wrong so fall back + // to generic outfits. JC + LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), + callback_choose_gender); + LLStartUp::setStartupState( STATE_CLEANUP ); } - LLInventoryModelBackgroundFetch::instance().start(); - LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); - if (cof - && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + + display_startup(); + + if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) { - // Special case, dupplicate request prevention. - // Cof folder will be requested via FetchCOF - // in appearance manager, prevent recursive fetch - cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); + if (gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("ClothingLoading"); + } + record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); + LLStartUp::setStartupState( STATE_CLEANUP ); + } + else if (gAgent.isFirstLogin() + && isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + // wait for avatar to be completely loaded + if (isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + } + else + { + // OK to just get the wearables + if ( gAgentWearables.areWearablesLoaded() ) + { + // We have our clothing, proceed. + LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } + //fall through this frame to STATE_CLEANUP + } + if (STATE_CLEANUP == LLStartUp::getStartupState()) + { + set_startup_status(1.0, "", ""); + display_startup(); - // It's debatable whether this flag is a good idea - sets all - // bits, and in general it isn't true that inventory - // initialization generates all types of changes. Maybe add an - // INITIALIZE mask bit instead? - gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); - gInventory.notifyObservers(); - - display_startup(); - - // set up callbacks - LL_INFOS() << "Registering Callbacks" << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - LL_INFOS() << " Inventory" << LL_ENDL; - LLInventoryModel::registerCallbacks(msg); - LL_INFOS() << " AvatarTracker" << LL_ENDL; - LLAvatarTracker::instance().registerCallbacks(msg); - LL_INFOS() << " Landmark" << LL_ENDL; - LLLandmark::registerCallbacks(msg); - display_startup(); - - // request all group information - LL_INFOS() << "Requesting Agent Data" << LL_ENDL; - gAgent.sendAgentDataUpdateRequest(); - display_startup(); - // Create the inventory views - LL_INFOS() << "Creating Inventory Views" << LL_ENDL; - LLFloaterReg::getInstance("inventory"); - display_startup(); - LLStartUp::setStartupState( STATE_MISC ); - display_startup(); - - return FALSE; - } - - - //--------------------------------------------------------------------- - // Misc - //--------------------------------------------------------------------- - if (STATE_MISC == LLStartUp::getStartupState()) - { - // We have a region, and just did a big inventory download. - // We can estimate the user's connection speed, and set their - // max bandwidth accordingly. JC - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) - { - // This is actually a pessimistic computation, because TCP may not have enough - // time to ramp up on the (small) default inventory file to truly measure max - // bandwidth. JC - F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); - const F32 FAST_RATE_BPS = 600.f * 1024.f; - const F32 FASTER_RATE_BPS = 750.f * 1024.f; - F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); - if (rate_bps > FASTER_RATE_BPS - && rate_bps > max_bandwidth) - { - LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " - << FASTER_RATE_BPS/1024.f - << " kbps" << LL_ENDL; - gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); - } - else if (rate_bps > FAST_RATE_BPS - && rate_bps > max_bandwidth) - { - LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " - << FAST_RATE_BPS/1024.f - << " kbps" << LL_ENDL; - gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); - } - - if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) - { - gSavedSettings.setBOOL("HelpFloaterOpen", TRUE); - } - - // Set the show start location to true, now that the user has logged - // on with this install. - gSavedSettings.setBOOL("ShowStartLocation", TRUE); - } - - display_startup(); + if (!mBenefitsSuccessfullyInit) + { + LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); + } - // Load stored local environment if needed. - LLEnvironment::instance().loadFromSettings(); + // Let the map know about the inventory. + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if(floater_world_map) + { + floater_world_map->observeInventory(&gInventory); + floater_world_map->observeFriends(); + } + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->resetBusyCount(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; + //gViewerWindow->revealIntroPanel(); + gViewerWindow->setStartupComplete(); + gViewerWindow->setProgressCancelButtonVisible(FALSE); + display_startup(); - // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) - //check_merchant_status(); + // We're not away from keyboard, even though login might have taken + // a while. JC + gAgent.clearAFK(); - display_startup(); - - if (gSavedSettings.getBOOL("HelpFloaterOpen")) - { - // show default topic - LLViewerHelp::instance().showTopic(""); - } - - display_startup(); - - // We're successfully logged in. - gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); - - LLFloaterReg::showInitialVisibleInstances(); - - LLFloaterGridStatus::getInstance()->startGridStatusTimer(); - - display_startup(); - - display_startup(); - // JC: Initializing audio requests many sounds for download. - init_audio(); - display_startup(); - - // JC: Initialize "active" gestures. This may also trigger - // many gesture downloads, if this is the user's first - // time on this machine or -purge has been run. - LLSD gesture_options - = LLLoginInstance::getInstance()->getResponse("gestures"); - if (gesture_options.isDefined()) - { - LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() - << LL_ENDL; - uuid_vec_t item_ids; - for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), - end = gesture_options.endArray(); resp_it != end; ++resp_it) - { - // If the id is not specifed in the LLSD, - // the LLSD operator[]() will return a null LLUUID. - LLUUID item_id = (*resp_it)["item_id"]; - LLUUID asset_id = (*resp_it)["asset_id"]; - - if (item_id.notNull() && asset_id.notNull()) - { - // Could schedule and delay these for later. - const BOOL no_inform_server = FALSE; - const BOOL no_deactivate_similar = FALSE; - LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, - no_inform_server, - no_deactivate_similar); - // We need to fetch the inventory items for these gestures - // so we have the names to populate the UI. - item_ids.push_back(item_id); - } - } - // no need to add gesture to inventory observer, it's already made in constructor - LLGestureMgr::instance().setFetchIDs(item_ids); - LLGestureMgr::instance().startFetch(); - } - gDisplaySwapBuffers = TRUE; - display_startup(); - - LLMessageSystem* msg = gMessageSystem; - msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); - msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); - msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); - msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); - - LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; - - LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; - gRenderStartTime.reset(); - gForegroundTime.reset(); - - // HACK: Inform simulator of window size. - // Do this here so it's less likely to race with RegisterNewAgent. - // TODO: Put this into RegisterNewAgent - // JC - 7/20/2002 - gViewerWindow->sendShapeToSim(); - - LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); - - // The reason we show the alert is because we want to - // reduce confusion for when you log in and your provided - // location is not your expected location. So, if this is - // your first login, then you do not have an expectation, - // thus, do not show this alert. - if (!gAgent.isFirstLogin()) - { - LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; - LLSLURL start_slurl = LLStartUp::getStartSLURL(); - LL_DEBUGS("AppInit") << "start slurl "< 1.f) && isAgentAvatarValid()) - { - LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); - } - else if (timeout_frac > 10.f) - { - // If we exceed the wait above while isAgentAvatarValid is - // not true yet, we will change startup state and - // eventually (once avatar does get created) wind up at - // the gender chooser. This should occur only in very - // unusual circumstances, so set the timeout fairly high - // to minimize mistaken hits here. - LL_WARNS() << "Wait for valid avatar state exceeded " - << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; - LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); - } - else - { - update_texture_fetch(); - set_startup_status(0.60f + 0.30f * timeout_frac, - LLTrans::getString("LoginPrecaching"), - gAgent.mMOTD.c_str()); - display_startup(); - } - - return TRUE; - } - - if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) - { - static LLFrameTimer wearables_timer; - - const F32 wearables_time = wearables_timer.getElapsedTimeF32(); - static LLCachedControl max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); - - if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) - { - // No point in waiting for clothing, we don't even know - // what outfit we want. Pop up a gender chooser dialog to - // ask and proceed to draw the world. JC - // - // *NOTE: We might hit this case even if we have an - // initial outfit, but if the load hasn't started - // already then something is wrong so fall back - // to generic outfits. JC - LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), - callback_choose_gender); - LLStartUp::setStartupState( STATE_CLEANUP ); - } - - display_startup(); - - if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) - { - if (gInventory.isInventoryUsable()) - { - LLNotificationsUtil::add("ClothingLoading"); - } - record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); - LLStartUp::setStartupState( STATE_CLEANUP ); - } - else if (gAgent.isFirstLogin() - && isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - // wait for avatar to be completely loaded - if (isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } - } - else - { - // OK to just get the wearables - if ( gAgentWearables.areWearablesLoaded() ) - { - // We have our clothing, proceed. - LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } - } - //fall through this frame to STATE_CLEANUP - } - - if (STATE_CLEANUP == LLStartUp::getStartupState()) - { - set_startup_status(1.0, "", ""); - display_startup(); - - if (!mBenefitsSuccessfullyInit) - { - LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); - } - - // Let the map know about the inventory. - LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); - if(floater_world_map) - { - floater_world_map->observeInventory(&gInventory); - floater_world_map->observeFriends(); - } - gViewerWindow->showCursor(); - gViewerWindow->getWindow()->resetBusyCount(); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; - //gViewerWindow->revealIntroPanel(); - gViewerWindow->setStartupComplete(); - gViewerWindow->setProgressCancelButtonVisible(FALSE); - display_startup(); - - // We're not away from keyboard, even though login might have taken - // a while. JC - gAgent.clearAFK(); - - // Have the agent start watching the friends list so we can update proxies - gAgent.observeFriends(); - - // Start automatic replay if the flag is set. - if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) - { - LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; - gAgentPilot.startPlayback(); - } - - show_debug_menus(); // Debug menu visiblity and First Use trigger - - // If we've got a startup URL, dispatch it - //LLStartUp::dispatchURL(); - - // Retrieve information about the land data - // (just accessing this the first time will fetch it, - // then the data is cached for the viewer's lifetime) - LLProductInfoRequestManager::instance(); - - // *FIX:Mani - What do I do here? - // Need we really clear the Auth response data? - // Clean up the userauth stuff. - // LLUserAuth::getInstance()->reset(); - - LLStartUp::setStartupState( STATE_STARTED ); - display_startup(); - - // Unmute audio if desired and setup volumes. - // This is a not-uncommon crash site, so surround it with - // LL_INFOS() output to aid diagnosis. - LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; - audio_update_volume(); - LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; - - // reset keyboard focus to sane state of pointing at world - gFocusMgr.setKeyboardFocus(NULL); - - LLAppViewer::instance()->handleLoginComplete(); - - LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); - - display_startup(); - - llassert(LLPathfindingManager::getInstance() != NULL); - LLPathfindingManager::getInstance()->initSystem(); - - gAgentAvatarp->sendHoverHeight(); - - // look for parcels we own - send_places_query(LLUUID::null, - LLUUID::null, - "", - DFQ_AGENT_OWNED, - LLParcel::C_ANY, - ""); - - LLUIUsage::instance().clear(); + // Have the agent start watching the friends list so we can update proxies + gAgent.observeFriends(); + + // Start automatic replay if the flag is set. + if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) + { + LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; + gAgentPilot.startPlayback(); + } + + show_debug_menus(); // Debug menu visiblity and First Use trigger + + // If we've got a startup URL, dispatch it + //LLStartUp::dispatchURL(); + + // Retrieve information about the land data + // (just accessing this the first time will fetch it, + // then the data is cached for the viewer's lifetime) + LLProductInfoRequestManager::instance(); + + // *FIX:Mani - What do I do here? + // Need we really clear the Auth response data? + // Clean up the userauth stuff. + // LLUserAuth::getInstance()->reset(); + + LLStartUp::setStartupState( STATE_STARTED ); + display_startup(); + + // Unmute audio if desired and setup volumes. + // This is a not-uncommon crash site, so surround it with + // LL_INFOS() output to aid diagnosis. + LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; + audio_update_volume(); + LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; + + // reset keyboard focus to sane state of pointing at world + gFocusMgr.setKeyboardFocus(NULL); + + LLAppViewer::instance()->handleLoginComplete(); + + LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); + + display_startup(); + + llassert(LLPathfindingManager::getInstance() != NULL); + LLPathfindingManager::getInstance()->initSystem(); + + gAgentAvatarp->sendHoverHeight(); + + // look for parcels we own + send_places_query(LLUUID::null, + LLUUID::null, + "", + DFQ_AGENT_OWNED, + LLParcel::C_ANY, + ""); + + LLUIUsage::instance().clear(); LLPerfStats::StatsRecorder::setAutotuneInit(); LLLUAmanager::runScriptOnLogin(); - return TRUE; - } + return TRUE; + } - return TRUE; + return TRUE; } // @@ -2434,50 +2434,50 @@ bool idle_startup() void login_show() { - LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; - - // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region - if (gToolBarView) - { - gToolBarView->setVisible(FALSE); - } - - LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); + LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; + + // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region + if (gToolBarView) + { + gToolBarView->setVisible(FALSE); + } + + LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); } // Callback for when login screen is closed. Option 0 = connect, option 1 = quit. void login_callback(S32 option, void *userdata) { - const S32 CONNECT_OPTION = 0; - const S32 QUIT_OPTION = 1; - - if (CONNECT_OPTION == option) - { - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - return; - } - else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION - { - if (!gSavedSettings.getBOOL("RememberPassword")) - { - // turn off the setting and write out to disk - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); - LLUIColorTable::instance().saveUserSettings(); - } - - // Next iteration through main loop should shut down the app cleanly. - LLAppViewer::instance()->userQuit(); - - if (LLAppViewer::instance()->quitRequested()) - { - LLPanelLogin::closePanel(); - } - return; - } - else - { - LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; - } + const S32 CONNECT_OPTION = 0; + const S32 QUIT_OPTION = 1; + + if (CONNECT_OPTION == option) + { + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + return; + } + else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION + { + if (!gSavedSettings.getBOOL("RememberPassword")) + { + // turn off the setting and write out to disk + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); + } + + // Next iteration through main loop should shut down the app cleanly. + LLAppViewer::instance()->userQuit(); + + if (LLAppViewer::instance()->quitRequested()) + { + LLPanelLogin::closePanel(); + } + return; + } + else + { + LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; + } } void release_notes_coro(const std::string url) @@ -2559,35 +2559,35 @@ void show_release_notes_if_required() void show_first_run_dialog() { - LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); + LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); } bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; - LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); - } - - LLPanelLogin::giveFocus(); - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; + LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); + } + + LLPanelLogin::giveFocus(); + return false; } void set_startup_status(const F32 frac, const std::string& string, const std::string& msg) { - gViewerWindow->setProgressPercent(frac*100); - gViewerWindow->setProgressString(string); + gViewerWindow->setProgressPercent(frac*100); + gViewerWindow->setProgressString(string); - gViewerWindow->setProgressMessage(msg); + gViewerWindow->setProgressMessage(msg); } bool login_alert_status(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // Buttons switch( option ) { @@ -2598,222 +2598,222 @@ bool login_alert_status(const LLSD& notification, const LLSD& response) // break; case 2: // Teleport // Restart the login process, starting at our home locaton - LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; default: LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL; } - LLPanelLogin::giveFocus(); - return false; + LLPanelLogin::giveFocus(); + return false; } void use_circuit_callback(void**, S32 result) { - // bail if we're quitting. - if(LLApp::isExiting()) return; - if( !gUseCircuitCallbackCalled ) - { - gUseCircuitCallbackCalled = true; - if (result) - { - // Make sure user knows something bad happened. JC - LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - if (gRememberPassword) - { - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); - } - else - { - LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); - } - reset_login(); - } - else - { - gGotUseCircuitCodeAck = true; - } - } + // bail if we're quitting. + if(LLApp::isExiting()) return; + if( !gUseCircuitCallbackCalled ) + { + gUseCircuitCallbackCalled = true; + if (result) + { + // Make sure user knows something bad happened. JC + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); + } + else + { + gGotUseCircuitCodeAck = true; + } + } } void register_viewer_callbacks(LLMessageSystem* msg) { - msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); - msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); - msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); - msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); - msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); - msg->setHandlerFunc("SimStats", process_sim_stats); - msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); - msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); - msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); - - msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); - msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); - msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); - msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); - msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); - msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); - - msg->setHandlerFunc("CrossedRegion", process_crossed_region); - msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); - - msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); - msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); - msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); - msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); - - msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); - msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); - msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); - msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); - msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); - msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); - msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); - msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); - msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); - - msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); - msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); - msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); - msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); - msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); - - msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); - msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); - msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); - msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); - msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, - &LLLiveLSLEditor::processScriptRunningReply); - - msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); - - msg->setHandlerFunc("LogoutReply", process_logout_reply); - - //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, - // &LLAgent::processAddModifyAbility); - //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, - // &LLAgent::processRemoveModifyAbility); - msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, - &LLAgent::processAgentDataUpdate); - msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, - &LLAgent::processAgentGroupDataUpdate); - msg->setHandlerFunc("AgentDropGroup", - &LLAgent::processAgentDropGroup); - // land ownership messages - msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, - LLViewerParcelMgr::processParcelOverlay); - msg->setHandlerFuncFast(_PREHASH_ParcelProperties, - LLViewerParcelMgr::processParcelProperties); - msg->setHandlerFunc("ParcelAccessListReply", - LLViewerParcelMgr::processParcelAccessListReply); - msg->setHandlerFunc("ParcelDwellReply", - LLViewerParcelMgr::processParcelDwellReply); - - msg->setHandlerFunc("AvatarPropertiesReply", - &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); - msg->setHandlerFunc("AvatarInterestsReply", - &LLAvatarPropertiesProcessor::processAvatarInterestsReply); - msg->setHandlerFunc("AvatarGroupsReply", - &LLAvatarPropertiesProcessor::processAvatarGroupsReply); - // ratings deprecated - //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, - // LLPanelAvatar::processAvatarStatisticsReply); - msg->setHandlerFunc("AvatarNotesReply", - &LLAvatarPropertiesProcessor::processAvatarNotesReply); - msg->setHandlerFunc("AvatarPicksReply", - &LLAvatarPropertiesProcessor::processAvatarPicksReply); - msg->setHandlerFunc("AvatarClassifiedReply", - &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); - - msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, - LLGroupMgr::processCreateGroupReply); - msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, - LLGroupMgr::processJoinGroupReply); - msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, - LLGroupMgr::processEjectGroupMemberReply); - msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, - LLGroupMgr::processLeaveGroupReply); - msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, - LLGroupMgr::processGroupPropertiesReply); - - // ratings deprecated - // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, - // LLFloaterRate::processReputationIndividualReply); - - msg->setHandlerFunc("ScriptControlChange", - LLAgent::processScriptControlChange ); - - msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); - - msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); - - msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, - LLPanelGroupLandMoney::processGroupAccountSummaryReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, - LLPanelGroupLandMoney::processGroupAccountDetailsReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, - LLPanelGroupLandMoney::processGroupAccountTransactionsReply); - - msg->setHandlerFuncFast(_PREHASH_UserInfoReply, - process_user_info_reply); - - msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); - - msg->setHandlerFunc("TeleportStart", process_teleport_start ); - msg->setHandlerFunc("TeleportProgress", process_teleport_progress); - msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); - msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); - - msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); - - msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, - LLGroupMgr::processGroupMembersReply); - msg->setHandlerFunc("GroupRoleDataReply", - LLGroupMgr::processGroupRoleDataReply); - msg->setHandlerFunc("GroupRoleMembersReply", - LLGroupMgr::processGroupRoleMembersReply); - msg->setHandlerFunc("GroupTitlesReply", - LLGroupMgr::processGroupTitlesReply); - // Special handler as this message is sometimes used for group land. - msg->setHandlerFunc("PlacesReply", process_places_reply); - msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); - - msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); - - msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); - msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); - msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); - - msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); - msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); - msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); - msg->setHandlerFunc("ScriptDialog", process_script_dialog); - msg->setHandlerFunc("LoadURL", process_load_url); - msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); - msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); - - // calling cards - msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); - msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); - msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); - - msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); - - msg->setHandlerFunc("InitiateDownload", process_initiate_download); - msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); + msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); + msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); + msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); + msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); + msg->setHandlerFunc("SimStats", process_sim_stats); + msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); + msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); + msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); + + msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); + msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); + msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); + msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); + msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); + msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); + + msg->setHandlerFunc("CrossedRegion", process_crossed_region); + msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); + + msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); + msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); + msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); + msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); + + msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); + msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); + msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); + msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); + msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); + msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); + msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); + msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); + + msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); + msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); + msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); + msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); + msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); + + msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); + msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); + msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); + msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); + msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, + &LLLiveLSLEditor::processScriptRunningReply); + + msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); + + msg->setHandlerFunc("LogoutReply", process_logout_reply); + + //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, + // &LLAgent::processAddModifyAbility); + //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, + // &LLAgent::processRemoveModifyAbility); + msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, + &LLAgent::processAgentDataUpdate); + msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, + &LLAgent::processAgentGroupDataUpdate); + msg->setHandlerFunc("AgentDropGroup", + &LLAgent::processAgentDropGroup); + // land ownership messages + msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, + LLViewerParcelMgr::processParcelOverlay); + msg->setHandlerFuncFast(_PREHASH_ParcelProperties, + LLViewerParcelMgr::processParcelProperties); + msg->setHandlerFunc("ParcelAccessListReply", + LLViewerParcelMgr::processParcelAccessListReply); + msg->setHandlerFunc("ParcelDwellReply", + LLViewerParcelMgr::processParcelDwellReply); + + msg->setHandlerFunc("AvatarPropertiesReply", + &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); + msg->setHandlerFunc("AvatarInterestsReply", + &LLAvatarPropertiesProcessor::processAvatarInterestsReply); + msg->setHandlerFunc("AvatarGroupsReply", + &LLAvatarPropertiesProcessor::processAvatarGroupsReply); + // ratings deprecated + //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, + // LLPanelAvatar::processAvatarStatisticsReply); + msg->setHandlerFunc("AvatarNotesReply", + &LLAvatarPropertiesProcessor::processAvatarNotesReply); + msg->setHandlerFunc("AvatarPicksReply", + &LLAvatarPropertiesProcessor::processAvatarPicksReply); + msg->setHandlerFunc("AvatarClassifiedReply", + &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); + + msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, + LLGroupMgr::processCreateGroupReply); + msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, + LLGroupMgr::processJoinGroupReply); + msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, + LLGroupMgr::processEjectGroupMemberReply); + msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, + LLGroupMgr::processLeaveGroupReply); + msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, + LLGroupMgr::processGroupPropertiesReply); + + // ratings deprecated + // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, + // LLFloaterRate::processReputationIndividualReply); + + msg->setHandlerFunc("ScriptControlChange", + LLAgent::processScriptControlChange ); + + msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); + + msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); + + msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, + LLPanelGroupLandMoney::processGroupAccountSummaryReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, + LLPanelGroupLandMoney::processGroupAccountDetailsReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, + LLPanelGroupLandMoney::processGroupAccountTransactionsReply); + + msg->setHandlerFuncFast(_PREHASH_UserInfoReply, + process_user_info_reply); + + msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); + + msg->setHandlerFunc("TeleportStart", process_teleport_start ); + msg->setHandlerFunc("TeleportProgress", process_teleport_progress); + msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); + msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); + + msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); + + msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, + LLGroupMgr::processGroupMembersReply); + msg->setHandlerFunc("GroupRoleDataReply", + LLGroupMgr::processGroupRoleDataReply); + msg->setHandlerFunc("GroupRoleMembersReply", + LLGroupMgr::processGroupRoleMembersReply); + msg->setHandlerFunc("GroupTitlesReply", + LLGroupMgr::processGroupTitlesReply); + // Special handler as this message is sometimes used for group land. + msg->setHandlerFunc("PlacesReply", process_places_reply); + msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); + + msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); + + msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); + msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); + msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); + + msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); + msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); + msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); + msg->setHandlerFunc("ScriptDialog", process_script_dialog); + msg->setHandlerFunc("LoadURL", process_load_url); + msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); + msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); + + // calling cards + msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); + msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); + msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); + + msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); + + msg->setHandlerFunc("InitiateDownload", process_initiate_download); + msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); msg->setHandlerFunc("GenericMessage", process_generic_message); msg->setHandlerFunc("GenericStreamingMessage", process_generic_streaming_message); msg->setHandlerFunc("LargeGenericMessage", process_large_generic_message); - msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); + msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32) { - // nothing + // nothing } const S32 OPT_CLOSED_WINDOW = -1; @@ -2821,27 +2821,27 @@ const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; const S32 OPT_TRUST_CERT = 0; const S32 OPT_CANCEL_TRUST = 1; - + bool callback_choose_gender(const LLSD& notification, const LLSD& response) { - - // These defaults are returned from the server on login. They are set in login.xml. - // If no default is returned from the server, they are retrieved from settings.xml. - - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case OPT_MALE: - LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); - break; - + + // These defaults are returned from the server on login. They are set in login.xml. + // If no default is returned from the server, they are retrieved from settings.xml. + + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_MALE: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); + break; + case OPT_FEMALE: case OPT_CLOSED_WINDOW: default: - LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); - break; - } - return false; + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); + break; + } + return false; } std::string get_screen_filename(const std::string& pattern) @@ -2873,66 +2873,66 @@ std::string LLStartUp::getScreenHomeFilename() //static void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, - const std::string& gender_name ) + const std::string& gender_name ) { - LL_DEBUGS() << "starting" << LL_ENDL; - - // Not going through the processAgentInitialWearables path, so need to set this here. - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - // Initiate creation of COF, since we're also bypassing that. - gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); - - ESex gender; - if (gender_name == "male") - { - LL_DEBUGS() << "male" << LL_ENDL; - gender = SEX_MALE; - } - else - { - LL_DEBUGS() << "female" << LL_ENDL; - gender = SEX_FEMALE; - } - - if (!isAgentAvatarValid()) - { - LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; - return; - } - - gAgentAvatarp->setSex(gender); - - // try to find the requested outfit or folder - - // -- check for existing outfit in My Outfits - bool do_copy = false; - LLUUID cat_id = findDescendentCategoryIDByName( - gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), - outfit_folder_name); - - // -- check for existing folder in Library - if (cat_id.isNull()) - { - cat_id = findDescendentCategoryIDByName( - gInventory.getLibraryRootFolderID(), - outfit_folder_name); - if (!cat_id.isNull()) - { - do_copy = true; - } - } - - if (cat_id.isNull()) - { - // -- final fallback: create standard wearables - LL_DEBUGS() << "standard wearables" << LL_ENDL; - gAgentWearables.createStandardWearables(); - } - else - { - bool do_append = false; - LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); - // Need to fetch cof contents before we can wear. + LL_DEBUGS() << "starting" << LL_ENDL; + + // Not going through the processAgentInitialWearables path, so need to set this here. + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + // Initiate creation of COF, since we're also bypassing that. + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + + ESex gender; + if (gender_name == "male") + { + LL_DEBUGS() << "male" << LL_ENDL; + gender = SEX_MALE; + } + else + { + LL_DEBUGS() << "female" << LL_ENDL; + gender = SEX_FEMALE; + } + + if (!isAgentAvatarValid()) + { + LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; + return; + } + + gAgentAvatarp->setSex(gender); + + // try to find the requested outfit or folder + + // -- check for existing outfit in My Outfits + bool do_copy = false; + LLUUID cat_id = findDescendentCategoryIDByName( + gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), + outfit_folder_name); + + // -- check for existing folder in Library + if (cat_id.isNull()) + { + cat_id = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + if (!cat_id.isNull()) + { + do_copy = true; + } + } + + if (cat_id.isNull()) + { + // -- final fallback: create standard wearables + LL_DEBUGS() << "standard wearables" << LL_ENDL; + gAgentWearables.createStandardWearables(); + } + else + { + bool do_append = false; + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + // Need to fetch cof contents before we can wear. if (do_copy) { callAfterCOFFetch(boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); @@ -2941,16 +2941,16 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, { callAfterCategoryLinksFetch(cat_id, boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); } - LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; - } + LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; + } - gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); } std::string& LLStartUp::getInitialOutfitName() { - return sInitialOutfit; + return sInitialOutfit; } std::string LLStartUp::getUserId() @@ -2966,8 +2966,8 @@ std::string LLStartUp::getUserId() // frees the bitmap void release_start_screen() { - LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; - gStartTexture = NULL; + LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; + gStartTexture = NULL; } @@ -2975,77 +2975,77 @@ void release_start_screen() std::string LLStartUp::startupStateToString(EStartupState state) { #define RTNENUM(E) case E: return #E - switch(state){ - RTNENUM( STATE_FIRST ); - RTNENUM( STATE_BROWSER_INIT ); - RTNENUM( STATE_LOGIN_SHOW ); - RTNENUM( STATE_LOGIN_WAIT ); - RTNENUM( STATE_LOGIN_CLEANUP ); - RTNENUM( STATE_LOGIN_AUTH_INIT ); - RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); - RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); - RTNENUM( STATE_WORLD_INIT ); - RTNENUM( STATE_MULTIMEDIA_INIT ); - RTNENUM( STATE_FONT_INIT ); - RTNENUM( STATE_SEED_GRANTED_WAIT ); - RTNENUM( STATE_SEED_CAP_GRANTED ); - RTNENUM( STATE_WORLD_WAIT ); - RTNENUM( STATE_AGENT_SEND ); - RTNENUM( STATE_AGENT_WAIT ); - RTNENUM( STATE_INVENTORY_SEND ); + switch(state){ + RTNENUM( STATE_FIRST ); + RTNENUM( STATE_BROWSER_INIT ); + RTNENUM( STATE_LOGIN_SHOW ); + RTNENUM( STATE_LOGIN_WAIT ); + RTNENUM( STATE_LOGIN_CLEANUP ); + RTNENUM( STATE_LOGIN_AUTH_INIT ); + RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); + RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); + RTNENUM( STATE_WORLD_INIT ); + RTNENUM( STATE_MULTIMEDIA_INIT ); + RTNENUM( STATE_FONT_INIT ); + RTNENUM( STATE_SEED_GRANTED_WAIT ); + RTNENUM( STATE_SEED_CAP_GRANTED ); + RTNENUM( STATE_WORLD_WAIT ); + RTNENUM( STATE_AGENT_SEND ); + RTNENUM( STATE_AGENT_WAIT ); + RTNENUM( STATE_INVENTORY_SEND ); RTNENUM(STATE_INVENTORY_CALLBACKS ); - RTNENUM( STATE_MISC ); - RTNENUM( STATE_PRECACHE ); - RTNENUM( STATE_WEARABLES_WAIT ); - RTNENUM( STATE_CLEANUP ); - RTNENUM( STATE_STARTED ); - default: - return llformat("(state #%d)", state); - } + RTNENUM( STATE_MISC ); + RTNENUM( STATE_PRECACHE ); + RTNENUM( STATE_WEARABLES_WAIT ); + RTNENUM( STATE_CLEANUP ); + RTNENUM( STATE_STARTED ); + default: + return llformat("(state #%d)", state); + } #undef RTNENUM } // static void LLStartUp::setStartupState( EStartupState state ) { - LL_INFOS("AppInit") << "Startup state changing from " << - getStartupStateString() << " to " << - startupStateToString(state) << LL_ENDL; + LL_INFOS("AppInit") << "Startup state changing from " << + getStartupStateString() << " to " << + startupStateToString(state) << LL_ENDL; - getPhases().stopPhase(getStartupStateString()); - gStartupState = state; - getPhases().startPhase(getStartupStateString()); + getPhases().stopPhase(getStartupStateString()); + gStartupState = state; + getPhases().startPhase(getStartupStateString()); - postStartupState(); + postStartupState(); } void LLStartUp::postStartupState() { - LLSD stateInfo; - stateInfo["str"] = getStartupStateString(); - stateInfo["enum"] = gStartupState; - sStateWatcher->post(stateInfo); - gDebugInfo["StartupState"] = getStartupStateString(); + LLSD stateInfo; + stateInfo["str"] = getStartupStateString(); + stateInfo["enum"] = gStartupState; + sStateWatcher->post(stateInfo); + gDebugInfo["StartupState"] = getStartupStateString(); } void reset_login() { - gAgentWearables.cleanup(); - gAgentCamera.cleanup(); - gAgent.cleanup(); + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + gAgent.cleanup(); gSky.cleanup(); // mVOSkyp is an inworld object. - LLWorld::getInstance()->resetClass(); + LLWorld::getInstance()->resetClass(); - if ( gViewerWindow ) - { // Hide menus and normal buttons - gViewerWindow->setNormalControlsVisible( FALSE ); - gLoginMenuBarView->setVisible( TRUE ); - gLoginMenuBarView->setEnabled( TRUE ); - } + if ( gViewerWindow ) + { // Hide menus and normal buttons + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + } - // Hide any other stuff - LLFloaterReg::hideVisibleInstances(); + // Hide any other stuff + LLFloaterReg::hideVisibleInstances(); LLStartUp::setStartupState( STATE_BROWSER_INIT ); if (LLVoiceClient::instanceExists()) @@ -3065,117 +3065,117 @@ void reset_login() // early, before the login screen). JC void LLStartUp::multimediaInit() { - LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingMultimedia"); - set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); + LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingMultimedia"); + set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); } void LLStartUp::fontInit() { - LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; - std::string msg = LLTrans::getString("LoginInitializingFonts"); - set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); - display_startup(); + LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingFonts"); + set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); - LLFontGL::loadDefaultFonts(); + LLFontGL::loadDefaultFonts(); } void LLStartUp::initNameCache() { - // Can be called multiple times - if ( gCacheName ) return; - - gCacheName = new LLCacheName(gMessageSystem); - gCacheName->addObserver(&callback_cache_name); - gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); - gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); - gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); - // Load stored cache if possible - LLAppViewer::instance()->loadNameCache(); - - // Start cache in not-running state until we figure out if we have - // capabilities for display name lookup - LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); - cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); - cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); - cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); + // Can be called multiple times + if ( gCacheName ) return; + + gCacheName = new LLCacheName(gMessageSystem); + gCacheName->addObserver(&callback_cache_name); + gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); + gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); + gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); + // Load stored cache if possible + LLAppViewer::instance()->loadNameCache(); + + // Start cache in not-running state until we figure out if we have + // capabilities for display name lookup + LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); + cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); + cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); + cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); } void LLStartUp::initExperiences() -{ +{ // Should trigger loading the cache. LLExperienceCache::instance().setCapabilityQuery( boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); - LLExperienceLog::instance().initialize(); + LLExperienceLog::instance().initialize(); } void LLStartUp::cleanupNameCache() { - delete gCacheName; - gCacheName = NULL; + delete gCacheName; + gCacheName = NULL; } bool LLStartUp::dispatchURL() { - // ok, if we've gotten this far and have a startup URL + // ok, if we've gotten this far and have a startup URL if (!getStartSLURL().isValid()) - { - return false; - } + { + return false; + } if(getStartSLURL().getType() != LLSLURL::APP) - { - - // If we started with a location, but we're already - // at that location, don't pop dialogs open. - LLVector3 pos = gAgent.getPositionAgent(); - LLVector3 slurlpos = getStartSLURL().getPosition(); - F32 dx = pos.mV[VX] - slurlpos.mV[VX]; - F32 dy = pos.mV[VY] - slurlpos.mV[VY]; - const F32 SLOP = 2.f; // meters - - if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() - || (dx*dx > SLOP*SLOP) - || (dy*dy > SLOP*SLOP) ) - { - LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, - NULL, false); - } - return true; - } - return false; + { + + // If we started with a location, but we're already + // at that location, don't pop dialogs open. + LLVector3 pos = gAgent.getPositionAgent(); + LLVector3 slurlpos = getStartSLURL().getPosition(); + F32 dx = pos.mV[VX] - slurlpos.mV[VX]; + F32 dy = pos.mV[VY] - slurlpos.mV[VY]; + const F32 SLOP = 2.f; // meters + + if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() + || (dx*dx > SLOP*SLOP) + || (dy*dy > SLOP*SLOP) ) + { + LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, + NULL, false); + } + return true; + } + return false; } -void LLStartUp::setStartSLURL(const LLSLURL& slurl) +void LLStartUp::setStartSLURL(const LLSLURL& slurl) { - LL_DEBUGS("AppInit")< socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); - std::string socks_user = socks_cred->getIdentifier()["username"].asString(); - std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); - - bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); - - if (!ok) - { - LLNotificationsUtil::add("SOCKS_BAD_CREDS"); - proxy_ok = false; - } - } - else if (auth_type.compare("None") == 0) - { - LLProxy::getInstance()->setAuthNone(); - } - else - { - LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; - - // Unknown or missing setting. - gSavedSettings.setString("Socks5AuthType", "None"); - - // Clear the SOCKS credentials. - LLPointer socks_cred = new LLCredential("SOCKS5"); - gSecAPIHandler->deleteCredential(socks_cred); - - LLProxy::getInstance()->setAuthNone(); - } - - if (proxy_ok) - { - // Start the proxy and check for errors - // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. - LLHost socks_host; - socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); - socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); - int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); - - if (status != SOCKS_OK) - { - LLSD subs; - subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); - subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); - - std::string error_string; - - switch(status) - { - case SOCKS_CONNECT_ERROR: // TCP Fail - error_string = "SOCKS_CONNECT_ERROR"; - break; - - case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection - error_string = "SOCKS_NOT_PERMITTED"; - break; - - case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server - error_string = "SOCKS_NOT_ACCEPTABLE"; - break; - - case SOCKS_AUTH_FAIL: // Authentication failed - error_string = "SOCKS_AUTH_FAIL"; - break; - - case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed - error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; - break; - - case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server - error_string = "SOCKS_HOST_CONNECT_FAILED"; - break; - - case SOCKS_INVALID_HOST: // Improperly formatted host address or port. - error_string = "SOCKS_INVALID_HOST"; - break; - - default: - error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, - LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; - break; - } - - LLNotificationsUtil::add(error_string, subs); - proxy_ok = false; - } - } - } - else - { - LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up - } - - if (proxy_ok) - { - // Determine the HTTP proxy type (if any) - if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) - { - LLHost http_host; - http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); - http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); - if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) - { - LLSD subs; - subs["HOST"] = http_host.getIPString(); - subs["PORT"] = (S32)http_host.getPort(); - LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); - proxy_ok = false; - } - } - else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) - { - LLHost socks_host; - socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); - socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); - if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) - { - LLSD subs; - subs["HOST"] = socks_host.getIPString(); - subs["PORT"] = (S32)socks_host.getPort(); - LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); - proxy_ok = false; - } - } - else if (httpProxyType.compare("None") == 0) - { - LLProxy::getInstance()->disableHTTPProxy(); - } - else - { - LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; - - // Set the missing or wrong configuration back to something valid. - gSavedSettings.setString("HttpProxyType", "None"); - LLProxy::getInstance()->disableHTTPProxy(); - - // Leave proxy_ok alone, since this isn't necessarily fatal. - } - } - - return proxy_ok; + bool proxy_ok = true; + std::string httpProxyType = gSavedSettings.getString("HttpProxyType"); + + // Set up SOCKS proxy (if needed) + if (gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + // Determine and update LLProxy with the saved authentication system + std::string auth_type = gSavedSettings.getString("Socks5AuthType"); + + if (auth_type.compare("UserPass") == 0) + { + LLPointer socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); + std::string socks_user = socks_cred->getIdentifier()["username"].asString(); + std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); + + bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); + + if (!ok) + { + LLNotificationsUtil::add("SOCKS_BAD_CREDS"); + proxy_ok = false; + } + } + else if (auth_type.compare("None") == 0) + { + LLProxy::getInstance()->setAuthNone(); + } + else + { + LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; + + // Unknown or missing setting. + gSavedSettings.setString("Socks5AuthType", "None"); + + // Clear the SOCKS credentials. + LLPointer socks_cred = new LLCredential("SOCKS5"); + gSecAPIHandler->deleteCredential(socks_cred); + + LLProxy::getInstance()->setAuthNone(); + } + + if (proxy_ok) + { + // Start the proxy and check for errors + // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. + LLHost socks_host; + socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); + + if (status != SOCKS_OK) + { + LLSD subs; + subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); + subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); + + std::string error_string; + + switch(status) + { + case SOCKS_CONNECT_ERROR: // TCP Fail + error_string = "SOCKS_CONNECT_ERROR"; + break; + + case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection + error_string = "SOCKS_NOT_PERMITTED"; + break; + + case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server + error_string = "SOCKS_NOT_ACCEPTABLE"; + break; + + case SOCKS_AUTH_FAIL: // Authentication failed + error_string = "SOCKS_AUTH_FAIL"; + break; + + case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed + error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; + break; + + case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server + error_string = "SOCKS_HOST_CONNECT_FAILED"; + break; + + case SOCKS_INVALID_HOST: // Improperly formatted host address or port. + error_string = "SOCKS_INVALID_HOST"; + break; + + default: + error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, + LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; + break; + } + + LLNotificationsUtil::add(error_string, subs); + proxy_ok = false; + } + } + } + else + { + LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up + } + + if (proxy_ok) + { + // Determine the HTTP proxy type (if any) + if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) + { + LLHost http_host; + http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); + http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); + if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) + { + LLSD subs; + subs["HOST"] = http_host.getIPString(); + subs["PORT"] = (S32)http_host.getPort(); + LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); + proxy_ok = false; + } + } + else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) + { + LLHost socks_host; + socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); + socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); + if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) + { + LLSD subs; + subs["HOST"] = socks_host.getIPString(); + subs["PORT"] = (S32)socks_host.getPort(); + LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); + proxy_ok = false; + } + } + else if (httpProxyType.compare("None") == 0) + { + LLProxy::getInstance()->disableHTTPProxy(); + } + else + { + LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; + + // Set the missing or wrong configuration back to something valid. + gSavedSettings.setString("HttpProxyType", "None"); + LLProxy::getInstance()->disableHTTPProxy(); + + // Leave proxy_ok alone, since this isn't necessarily fatal. + } + } + + return proxy_ok; } bool login_alert_done(const LLSD& notification, const LLSD& response) { - LLPanelLogin::giveFocus(); - return false; + LLPanelLogin::giveFocus(); + return false; } -// parse the certificate information into args for the +// parse the certificate information into args for the // certificate notifications LLSD transform_cert_args(LLPointer cert) { - LLSD args = LLSD::emptyMap(); - std::string value; - LLSD cert_info; - cert->getLLSD(cert_info); - // convert all of the elements in the cert into - // args for the xml dialog, so we have flexability to - // display various parts of the cert by only modifying - // the cert alert dialog xml. - for(LLSD::map_iterator iter = cert_info.beginMap(); - iter != cert_info.endMap(); - iter++) - { - // key usage and extended key usage - // are actually arrays, and we want to format them as comma separated - // strings, so special case those. - LLSDSerialize::toXML(cert_info[iter->first], std::cout); - if((iter->first == std::string(CERT_KEY_USAGE)) || - (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) - { - value = ""; - LLSD usage = cert_info[iter->first]; - for (LLSD::array_iterator usage_iter = usage.beginArray(); - usage_iter != usage.endArray(); - usage_iter++) - { - - if(usage_iter != usage.beginArray()) - { - value += ", "; - } - - value += (*usage_iter).asString(); - } - - } - else - { - value = iter->second.asString(); - } - - std::string name = iter->first; - std::transform(name.begin(), name.end(), name.begin(), - (int(*)(int))toupper); - args[name.c_str()] = value; - } - return args; + LLSD args = LLSD::emptyMap(); + std::string value; + LLSD cert_info; + cert->getLLSD(cert_info); + // convert all of the elements in the cert into + // args for the xml dialog, so we have flexability to + // display various parts of the cert by only modifying + // the cert alert dialog xml. + for(LLSD::map_iterator iter = cert_info.beginMap(); + iter != cert_info.endMap(); + iter++) + { + // key usage and extended key usage + // are actually arrays, and we want to format them as comma separated + // strings, so special case those. + LLSDSerialize::toXML(cert_info[iter->first], std::cout); + if((iter->first == std::string(CERT_KEY_USAGE)) || + (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) + { + value = ""; + LLSD usage = cert_info[iter->first]; + for (LLSD::array_iterator usage_iter = usage.beginArray(); + usage_iter != usage.endArray(); + usage_iter++) + { + + if(usage_iter != usage.beginArray()) + { + value += ", "; + } + + value += (*usage_iter).asString(); + } + + } + else + { + value = iter->second.asString(); + } + + std::string name = iter->first; + std::transform(name.begin(), name.end(), name.begin(), + (int(*)(int))toupper); + args[name.c_str()] = value; + } + return args; } // when we handle a cert error, give focus back to the login panel void general_cert_done(const LLSD& notification, const LLSD& response) { - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - LLPanelLogin::giveFocus(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + LLPanelLogin::giveFocus(); } // check to see if the user wants to trust the cert. -// if they do, add it to the cert store and +// if they do, add it to the cert store and void trust_cert_done(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case OPT_TRUST_CERT: - { - LLPointer cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); - LLPointer store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); - store->add(cert); - store->save(); - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - break; - } - case OPT_CANCEL_TRUST: - reset_login(); - gSavedSettings.setBOOL("AutoLogin", FALSE); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - default: - LLPanelLogin::giveFocus(); - break; - } + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_TRUST_CERT: + { + LLPointer cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); + LLPointer store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); + store->add(cert); + store->save(); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + break; + } + case OPT_CANCEL_TRUST: + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + default: + LLPanelLogin::giveFocus(); + break; + } } void apply_udp_blacklist(const std::string& csv) { - std::string::size_type start = 0; - std::string::size_type comma = 0; - do - { - comma = csv.find(",", start); - if (comma == std::string::npos) - { - comma = csv.length(); - } - std::string item(csv, start, comma-start); - - LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; - gMessageSystem->banUdpMessage(item); - - start = comma + 1; - - } - while(comma < csv.length()); - + std::string::size_type start = 0; + std::string::size_type comma = 0; + do + { + comma = csv.find(",", start); + if (comma == std::string::npos) + { + comma = csv.length(); + } + std::string item(csv, start, comma-start); + + LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; + gMessageSystem->banUdpMessage(item); + + start = comma + 1; + + } + while(comma < csv.length()); + } void on_benefits_failed_callback(const LLSD& notification, const LLSD& response) { - LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; + LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; } bool init_benefits(LLSD& response) { - bool succ = true; - - std::string package_name = response["account_type"].asString(); - const LLSD& benefits_sd = response["account_level_benefits"]; - if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || - !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) - { - succ = false; - } - else - { - LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; - } - const LLSD& packages_sd = response["premium_packages"]; - for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); - package_iter != packages_sd.endMap(); - ++package_iter) - { - std::string package_name = package_iter->first; - const LLSD& benefits_sd = package_iter->second["benefits"]; - if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) - { - LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; - } - else - { - LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; - succ = false; - } - } - - if (!LLAgentBenefitsMgr::has("Base")) - { - LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; - succ = false; - } - if (!LLAgentBenefitsMgr::has("Premium")) - { - LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; - succ = false; - } - - return succ; + bool succ = true; + + std::string package_name = response["account_type"].asString(); + const LLSD& benefits_sd = response["account_level_benefits"]; + if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || + !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) + { + succ = false; + } + else + { + LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; + } + const LLSD& packages_sd = response["premium_packages"]; + for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); + package_iter != packages_sd.endMap(); + ++package_iter) + { + std::string package_name = package_iter->first; + const LLSD& benefits_sd = package_iter->second["benefits"]; + if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) + { + LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; + } + else + { + LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; + succ = false; + } + } + + if (!LLAgentBenefitsMgr::has("Base")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; + succ = false; + } + if (!LLAgentBenefitsMgr::has("Premium")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; + succ = false; + } + + return succ; } bool process_login_success_response() { - LLSD response = LLLoginInstance::getInstance()->getResponse(); - - mBenefitsSuccessfullyInit = init_benefits(response); - - std::string text(response["udp_blacklist"]); - if(!text.empty()) - { - apply_udp_blacklist(text); - } - - // unpack login data needed by the application - text = response["agent_id"].asString(); - if(!text.empty()) gAgentID.set(text); - gDebugInfo["AgentID"] = text; - - LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); - LLPerfStats::StatsRecorder::setFocusAv(gAgentID); - - // Agent id needed for parcel info request in LLUrlEntryParcel - // to resolve parcel name. - LLUrlEntryParcel::setAgentID(gAgentID); - - text = response["session_id"].asString(); - if(!text.empty()) gAgentSessionID.set(text); - gDebugInfo["SessionID"] = text; - - // Session id needed for parcel info request in LLUrlEntryParcel - // to resolve parcel name. - LLUrlEntryParcel::setSessionID(gAgentSessionID); - - text = response["secure_session_id"].asString(); - if(!text.empty()) gAgent.mSecureSessionID.set(text); - - // if the response contains a display name, use that, - // otherwise if the response contains a first and/or last name, - // use those. Otherwise use the credential identifier - - gDisplayName = ""; - if (response.has("display_name")) - { - gDisplayName.assign(response["display_name"].asString()); - if(!gDisplayName.empty()) - { - // Remove quotes from string. Login.cgi sends these to force - // names that look like numbers into strings. - LLStringUtil::replaceChar(gDisplayName, '"', ' '); - LLStringUtil::trim(gDisplayName); - } - } - std::string first_name; - if(response.has("first_name")) - { - first_name = response["first_name"].asString(); - LLStringUtil::replaceChar(first_name, '"', ' '); - LLStringUtil::trim(first_name); - gAgentUsername = first_name; - } - - if(response.has("last_name") && !gAgentUsername.empty()) - { - std::string last_name = response["last_name"].asString(); - if (last_name != "Resident") - { - LLStringUtil::replaceChar(last_name, '"', ' '); - LLStringUtil::trim(last_name); - gAgentUsername = gAgentUsername + " " + last_name; - } - } - - if(gDisplayName.empty()) - { - if(response.has("first_name")) - { - gDisplayName.assign(response["first_name"].asString()); - LLStringUtil::replaceChar(gDisplayName, '"', ' '); - LLStringUtil::trim(gDisplayName); - } - if(response.has("last_name")) - { - text.assign(response["last_name"].asString()); - LLStringUtil::replaceChar(text, '"', ' '); - LLStringUtil::trim(text); - if(!gDisplayName.empty()) - { - gDisplayName += " "; - } - gDisplayName += text; - } - } - - if(gDisplayName.empty()) - { - gDisplayName.assign(gUserCredential->asString()); - } - - // this is their actual ability to access content - text = response["agent_access_max"].asString(); - if (!text.empty()) - { - // agent_access can be 'A', 'M', and 'PG'. - gAgent.setMaturity(text[0]); - } - - // this is the value of their preference setting for that content - // which will always be <= agent_access_max - text = response["agent_region_access"].asString(); - if (!text.empty()) - { - U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); - - gSavedSettings.setU32("PreferredMaturity", preferredMaturity); - } - - text = response["start_location"].asString(); - if(!text.empty()) - { - gAgentStartLocation.assign(text); - } - - text = response["circuit_code"].asString(); - if(!text.empty()) - { - gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); - } - std::string sim_ip_str = response["sim_ip"]; - std::string sim_port_str = response["sim_port"]; - if(!sim_ip_str.empty() && !sim_port_str.empty()) - { - U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); - gFirstSim.set(sim_ip_str, sim_port); - if (gFirstSim.isOk()) - { - gMessageSystem->enableCircuit(gFirstSim, TRUE); - } - } - std::string region_x_str = response["region_x"]; - std::string region_y_str = response["region_y"]; - if(!region_x_str.empty() && !region_y_str.empty()) - { - U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); - U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); - gFirstSimHandle = to_region_handle(region_x, region_y); - } - - const std::string look_at_str = response["look_at"]; - if (!look_at_str.empty()) - { - size_t len = look_at_str.size(); - LLMemoryStream mstr((U8*)look_at_str.c_str(), len); - LLSD sd = LLSDSerialize::fromNotation(mstr, len); - gAgentStartLookAt = ll_vector3_from_sd(sd); - } - - text = response["seed_capability"].asString(); - if (!text.empty()) gFirstSimSeedCap = text; - - text = response["seconds_since_epoch"].asString(); - if(!text.empty()) - { - U32 server_utc_time = strtoul(text.c_str(), NULL, 10); - if(server_utc_time) - { - time_t now = time(NULL); - gUTCOffset = (server_utc_time - now); - - // Print server timestamp - LLSD substitution; - substitution["datetime"] = (S32)server_utc_time; - std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; - LLStringUtil::format(timeStr, substitution); - LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; - } - } - - // this is the base used to construct help URLs - text = response["help_url_format"].asString(); - if (!text.empty()) - { - // replace the default help URL format - gSavedSettings.setString("HelpURLFormat",text); - } - - std::string home_location = response["home"]; - if(!home_location.empty()) - { - size_t len = home_location.size(); - LLMemoryStream mstr((U8*)home_location.c_str(), len); - LLSD sd = LLSDSerialize::fromNotation(mstr, len); - S32 region_x = sd["region_handle"][0].asInteger(); - S32 region_y = sd["region_handle"][1].asInteger(); - U64 region_handle = to_region_handle(region_x, region_y); - LLVector3 position = ll_vector3_from_sd(sd["position"]); - gAgent.setHomePosRegion(region_handle, position); - } - - gAgent.mMOTD.assign(response["message"]); - - // Options... - // Each 'option' is an array of submaps. - // It appears that we only ever use the first element of the array. - LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; - if(inv_root_folder_id.notNull()) - { - gInventory.setRootFolderID(inv_root_folder_id); - //gInventory.mock(gAgent.getInventoryRootID()); - } - - LLSD login_flags = response["login-flags"][0]; - if(login_flags.size()) - { - std::string flag = login_flags["ever_logged_in"]; - if(!flag.empty()) - { - gAgent.setFirstLogin(flag == "N"); - } - - /* Flag is currently ignored by the viewer. - flag = login_flags["stipend_since_login"]; - if(flag == "Y") - { - stipend_since_login = true; - } - */ - - flag = login_flags["gendered"].asString(); - if(flag == "Y") - { - // We don't care about this flag anymore; now base whether - // outfit is chosen on COF contents, initial outfit - // requested and available, etc. - - //gAgent.setGenderChosen(TRUE); - } - - bool pacific_daylight_time = false; - flag = login_flags["daylight_savings"].asString(); - if(flag == "Y") - { - pacific_daylight_time = (flag == "Y"); - } - - //setup map of datetime strings to codes and slt & local time offset from utc - LLStringOps::setupDatetimeInfo(pacific_daylight_time); - } - - // set up the voice configuration. Ultimately, we should pass this up as part of each voice - // channel if we need to move to multiple voice servers per grid. - LLSD voice_config_info = response["voice-config"]; - if(voice_config_info.has("VoiceServerType")) - { - gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); - } - - // Request the map server url - std::string map_server_url = response["map-server-url"]; - if(!map_server_url.empty()) - { - // We got an answer from the grid -> use that for map for the current session - gSavedSettings.setString("CurrentMapServerURL", map_server_url); - LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; - } - else - { - // No answer from the grid -> use the default setting for current session - map_server_url = gSavedSettings.getString("MapServerURL"); - gSavedSettings.setString("CurrentMapServerURL", map_server_url); - LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; - } - - // Default male and female avatars allowing the user to choose their avatar on first login. - // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard - // "new ruth." Not to be confused with 'initial-outfit' below - LLSD newuser_config = response["newuser-config"][0]; - if(newuser_config.has("DefaultFemaleAvatar")) - { - gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); - } - if(newuser_config.has("DefaultMaleAvatar")) - { - gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); - } - - // Initial outfit for the user. - LLSD initial_outfit = response["initial-outfit"][0]; - if(initial_outfit.size()) - { - std::string flag = initial_outfit["folder_name"]; - if(!flag.empty()) - { - // Initial outfit is a folder in your inventory, - // must be an exact folder-name match. - sInitialOutfit = flag; - } - - flag = initial_outfit["gender"].asString(); - if(!flag.empty()) - { - sInitialOutfitGender = flag; - } - } - - std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); - if (!fake_initial_outfit_name.empty()) - { - gAgent.setFirstLogin(true); - sInitialOutfit = fake_initial_outfit_name; - if (sInitialOutfitGender.empty()) - { - sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. - } - - LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; - } - - // set the location of the Agent Appearance service, from which we can request - // avatar baked textures if they are supported by the current region - std::string agent_appearance_url = response["agent_appearance_service"]; - if (!agent_appearance_url.empty()) - { - LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); - } - - // Set the location of the snapshot sharing config endpoint - std::string snapshot_config_url = response["snapshot_config_url"]; - if(!snapshot_config_url.empty()) - { - gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); - } - - // Start the process of fetching the OpenID session cookie for this user login - std::string openid_url = response["openid_url"]; - if(!openid_url.empty()) - { - std::string openid_token = response["openid_token"]; - LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); - } - - - // Only save mfa_hash for future logins if the user wants their info remembered. - if(response.has("mfa_hash") + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + mBenefitsSuccessfullyInit = init_benefits(response); + + std::string text(response["udp_blacklist"]); + if(!text.empty()) + { + apply_udp_blacklist(text); + } + + // unpack login data needed by the application + text = response["agent_id"].asString(); + if(!text.empty()) gAgentID.set(text); + gDebugInfo["AgentID"] = text; + + LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); + LLPerfStats::StatsRecorder::setFocusAv(gAgentID); + + // Agent id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setAgentID(gAgentID); + + text = response["session_id"].asString(); + if(!text.empty()) gAgentSessionID.set(text); + gDebugInfo["SessionID"] = text; + + // Session id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setSessionID(gAgentSessionID); + + text = response["secure_session_id"].asString(); + if(!text.empty()) gAgent.mSecureSessionID.set(text); + + // if the response contains a display name, use that, + // otherwise if the response contains a first and/or last name, + // use those. Otherwise use the credential identifier + + gDisplayName = ""; + if (response.has("display_name")) + { + gDisplayName.assign(response["display_name"].asString()); + if(!gDisplayName.empty()) + { + // Remove quotes from string. Login.cgi sends these to force + // names that look like numbers into strings. + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + } + std::string first_name; + if(response.has("first_name")) + { + first_name = response["first_name"].asString(); + LLStringUtil::replaceChar(first_name, '"', ' '); + LLStringUtil::trim(first_name); + gAgentUsername = first_name; + } + + if(response.has("last_name") && !gAgentUsername.empty()) + { + std::string last_name = response["last_name"].asString(); + if (last_name != "Resident") + { + LLStringUtil::replaceChar(last_name, '"', ' '); + LLStringUtil::trim(last_name); + gAgentUsername = gAgentUsername + " " + last_name; + } + } + + if(gDisplayName.empty()) + { + if(response.has("first_name")) + { + gDisplayName.assign(response["first_name"].asString()); + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + if(response.has("last_name")) + { + text.assign(response["last_name"].asString()); + LLStringUtil::replaceChar(text, '"', ' '); + LLStringUtil::trim(text); + if(!gDisplayName.empty()) + { + gDisplayName += " "; + } + gDisplayName += text; + } + } + + if(gDisplayName.empty()) + { + gDisplayName.assign(gUserCredential->asString()); + } + + // this is their actual ability to access content + text = response["agent_access_max"].asString(); + if (!text.empty()) + { + // agent_access can be 'A', 'M', and 'PG'. + gAgent.setMaturity(text[0]); + } + + // this is the value of their preference setting for that content + // which will always be <= agent_access_max + text = response["agent_region_access"].asString(); + if (!text.empty()) + { + U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); + + gSavedSettings.setU32("PreferredMaturity", preferredMaturity); + } + + text = response["start_location"].asString(); + if(!text.empty()) + { + gAgentStartLocation.assign(text); + } + + text = response["circuit_code"].asString(); + if(!text.empty()) + { + gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); + } + std::string sim_ip_str = response["sim_ip"]; + std::string sim_port_str = response["sim_port"]; + if(!sim_ip_str.empty() && !sim_port_str.empty()) + { + U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); + gFirstSim.set(sim_ip_str, sim_port); + if (gFirstSim.isOk()) + { + gMessageSystem->enableCircuit(gFirstSim, TRUE); + } + } + std::string region_x_str = response["region_x"]; + std::string region_y_str = response["region_y"]; + if(!region_x_str.empty() && !region_y_str.empty()) + { + U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); + U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); + gFirstSimHandle = to_region_handle(region_x, region_y); + } + + const std::string look_at_str = response["look_at"]; + if (!look_at_str.empty()) + { + size_t len = look_at_str.size(); + LLMemoryStream mstr((U8*)look_at_str.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + gAgentStartLookAt = ll_vector3_from_sd(sd); + } + + text = response["seed_capability"].asString(); + if (!text.empty()) gFirstSimSeedCap = text; + + text = response["seconds_since_epoch"].asString(); + if(!text.empty()) + { + U32 server_utc_time = strtoul(text.c_str(), NULL, 10); + if(server_utc_time) + { + time_t now = time(NULL); + gUTCOffset = (server_utc_time - now); + + // Print server timestamp + LLSD substitution; + substitution["datetime"] = (S32)server_utc_time; + std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; + LLStringUtil::format(timeStr, substitution); + LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; + } + } + + // this is the base used to construct help URLs + text = response["help_url_format"].asString(); + if (!text.empty()) + { + // replace the default help URL format + gSavedSettings.setString("HelpURLFormat",text); + } + + std::string home_location = response["home"]; + if(!home_location.empty()) + { + size_t len = home_location.size(); + LLMemoryStream mstr((U8*)home_location.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + S32 region_x = sd["region_handle"][0].asInteger(); + S32 region_y = sd["region_handle"][1].asInteger(); + U64 region_handle = to_region_handle(region_x, region_y); + LLVector3 position = ll_vector3_from_sd(sd["position"]); + gAgent.setHomePosRegion(region_handle, position); + } + + gAgent.mMOTD.assign(response["message"]); + + // Options... + // Each 'option' is an array of submaps. + // It appears that we only ever use the first element of the array. + LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; + if(inv_root_folder_id.notNull()) + { + gInventory.setRootFolderID(inv_root_folder_id); + //gInventory.mock(gAgent.getInventoryRootID()); + } + + LLSD login_flags = response["login-flags"][0]; + if(login_flags.size()) + { + std::string flag = login_flags["ever_logged_in"]; + if(!flag.empty()) + { + gAgent.setFirstLogin(flag == "N"); + } + + /* Flag is currently ignored by the viewer. + flag = login_flags["stipend_since_login"]; + if(flag == "Y") + { + stipend_since_login = true; + } + */ + + flag = login_flags["gendered"].asString(); + if(flag == "Y") + { + // We don't care about this flag anymore; now base whether + // outfit is chosen on COF contents, initial outfit + // requested and available, etc. + + //gAgent.setGenderChosen(TRUE); + } + + bool pacific_daylight_time = false; + flag = login_flags["daylight_savings"].asString(); + if(flag == "Y") + { + pacific_daylight_time = (flag == "Y"); + } + + //setup map of datetime strings to codes and slt & local time offset from utc + LLStringOps::setupDatetimeInfo(pacific_daylight_time); + } + + // set up the voice configuration. Ultimately, we should pass this up as part of each voice + // channel if we need to move to multiple voice servers per grid. + LLSD voice_config_info = response["voice-config"]; + if(voice_config_info.has("VoiceServerType")) + { + gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); + } + + // Request the map server url + std::string map_server_url = response["map-server-url"]; + if(!map_server_url.empty()) + { + // We got an answer from the grid -> use that for map for the current session + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; + } + else + { + // No answer from the grid -> use the default setting for current session + map_server_url = gSavedSettings.getString("MapServerURL"); + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; + } + + // Default male and female avatars allowing the user to choose their avatar on first login. + // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard + // "new ruth." Not to be confused with 'initial-outfit' below + LLSD newuser_config = response["newuser-config"][0]; + if(newuser_config.has("DefaultFemaleAvatar")) + { + gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); + } + if(newuser_config.has("DefaultMaleAvatar")) + { + gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); + } + + // Initial outfit for the user. + LLSD initial_outfit = response["initial-outfit"][0]; + if(initial_outfit.size()) + { + std::string flag = initial_outfit["folder_name"]; + if(!flag.empty()) + { + // Initial outfit is a folder in your inventory, + // must be an exact folder-name match. + sInitialOutfit = flag; + } + + flag = initial_outfit["gender"].asString(); + if(!flag.empty()) + { + sInitialOutfitGender = flag; + } + } + + std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); + if (!fake_initial_outfit_name.empty()) + { + gAgent.setFirstLogin(true); + sInitialOutfit = fake_initial_outfit_name; + if (sInitialOutfitGender.empty()) + { + sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. + } + + LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; + } + + // set the location of the Agent Appearance service, from which we can request + // avatar baked textures if they are supported by the current region + std::string agent_appearance_url = response["agent_appearance_service"]; + if (!agent_appearance_url.empty()) + { + LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); + } + + // Set the location of the snapshot sharing config endpoint + std::string snapshot_config_url = response["snapshot_config_url"]; + if(!snapshot_config_url.empty()) + { + gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); + } + + // Start the process of fetching the OpenID session cookie for this user login + std::string openid_url = response["openid_url"]; + if(!openid_url.empty()) + { + std::string openid_token = response["openid_token"]; + LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); + } + + + // Only save mfa_hash for future logins if the user wants their info remembered. + if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && LLLoginInstance::getInstance()->saveMFA()) - { - std::string grid(LLGridManager::getInstance()->getGridId()); - std::string user_id(gUserCredential->userID()); - gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); - // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically - gSecAPIHandler->syncProtectedMap(); - } + { + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id(gUserCredential->userID()); + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); + // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically + gSecAPIHandler->syncProtectedMap(); + } else if (!LLLoginInstance::getInstance()->saveMFA()) { std::string grid(LLGridManager::getInstance()->getGridId()); @@ -3870,26 +3870,26 @@ bool process_login_success_response() gSecAPIHandler->syncProtectedMap(); } - bool success = false; - // JC: gesture loading done below, when we have an asset system - // in place. Don't delete/clear gUserCredentials until then. - if(gAgentID.notNull() - && gAgentSessionID.notNull() - && gMessageSystem->mOurCircuitCode - && gFirstSim.isOk() - && gInventory.getRootFolderID().notNull()) - { - success = true; - } + bool success = false; + // JC: gesture loading done below, when we have an asset system + // in place. Don't delete/clear gUserCredentials until then. + if(gAgentID.notNull() + && gAgentSessionID.notNull() + && gMessageSystem->mOurCircuitCode + && gFirstSim.isOk() + && gInventory.getRootFolderID().notNull()) + { + success = true; + } LLAppViewer* pApp = LLAppViewer::instance(); - pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. - return success; + pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. + return success; } void transition_back_to_login_panel(const std::string& emsg) { - // Bounce back to the login screen. - reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - gSavedSettings.setBOOL("AutoLogin", FALSE); + // Bounce back to the login screen. + reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + gSavedSettings.setBOOL("AutoLogin", FALSE); } diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index d2a650f200..5fc0ea855e 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltoast.cpp * @brief This class implements a placeholder for any notification panel. * * $LicenseInfo:firstyear=2000&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$ */ @@ -38,8 +38,8 @@ std::list LLToast::sModalToastsList; //-------------------------------------------------------------------------- LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period) - : mToast(toast), - LLEventTimer(period) + : mToast(toast), + LLEventTimer(period) { } @@ -51,159 +51,159 @@ bool LLToastLifeTimer::tick() void LLToastLifeTimer::restart() { - // start() discards any previously-running mTimer - start(); + // start() discards any previously-running mTimer + start(); } bool LLToastLifeTimer::getStarted() { - return isRunning(); + return isRunning(); } void LLToastLifeTimer::setPeriod(F32 period) { - mPeriod = period; + mPeriod = period; } /*==========================================================================*| F32 LLToastLifeTimer::getRemainingTimeF32() { - F32 et = mEventTimer.getElapsedTimeF32(); - if (!getStarted() || et > mPeriod) return 0.0f; - return mPeriod - et; + F32 et = mEventTimer.getElapsedTimeF32(); + if (!getStarted() || et > mPeriod) return 0.0f; + return mPeriod - et; } |*==========================================================================*/ //-------------------------------------------------------------------------- -LLToast::Params::Params() -: can_fade("can_fade", true), - can_be_stored("can_be_stored", true), - is_modal("is_modal", false), - is_tip("is_tip", false), - enable_hide_btn("enable_hide_btn", true), - force_show("force_show", false), - force_store("force_store", false), - fading_time_secs("fading_time_secs", gSavedSettings.getS32("ToastFadingTime")), - lifetime_secs("lifetime_secs", gSavedSettings.getS32("NotificationToastLifeTime")) +LLToast::Params::Params() +: can_fade("can_fade", true), + can_be_stored("can_be_stored", true), + is_modal("is_modal", false), + is_tip("is_tip", false), + enable_hide_btn("enable_hide_btn", true), + force_show("force_show", false), + force_store("force_store", false), + fading_time_secs("fading_time_secs", gSavedSettings.getS32("ToastFadingTime")), + lifetime_secs("lifetime_secs", gSavedSettings.getS32("NotificationToastLifeTime")) {}; -LLToast::LLToast(const LLToast::Params& p) -: LLModalDialog(LLSD(), p.is_modal), - mToastLifetime(p.lifetime_secs), - mToastFadingTime(p.fading_time_secs), - mNotificationID(p.notif_id), - mSessionID(p.session_id), - mCanFade(p.can_fade), - mCanBeStored(p.can_be_stored), - mHideBtnEnabled(p.enable_hide_btn), - mHideBtn(NULL), - mPanel(NULL), - mNotification(p.notification), - mIsHidden(false), - mHideBtnPressed(false), - mIsTip(p.is_tip), - mWrapperPanel(NULL), - mIsFading(false), - mIsHovered(false) -{ - mTimer.reset(new LLToastLifeTimer(this, p.lifetime_secs)); - - buildFromFile("panel_toast.xml"); - - setCanDrag(FALSE); - - mWrapperPanel = getChild("wrapper_panel"); - - setBackgroundOpaque(TRUE); // *TODO: obsolete - updateTransparency(); - - if(p.panel()) - { - insertPanel(p.panel); - } - - if(mHideBtnEnabled) - { - mHideBtn = getChild("hide_btn"); - mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); - } - - // init callbacks if present - if(!p.on_delete_toast().empty()) - { - mOnDeleteToastSignal.connect(p.on_delete_toast()); - } - - if (isModal()) - { - sModalToastsList.push_front(this); - } +LLToast::LLToast(const LLToast::Params& p) +: LLModalDialog(LLSD(), p.is_modal), + mToastLifetime(p.lifetime_secs), + mToastFadingTime(p.fading_time_secs), + mNotificationID(p.notif_id), + mSessionID(p.session_id), + mCanFade(p.can_fade), + mCanBeStored(p.can_be_stored), + mHideBtnEnabled(p.enable_hide_btn), + mHideBtn(NULL), + mPanel(NULL), + mNotification(p.notification), + mIsHidden(false), + mHideBtnPressed(false), + mIsTip(p.is_tip), + mWrapperPanel(NULL), + mIsFading(false), + mIsHovered(false) +{ + mTimer.reset(new LLToastLifeTimer(this, p.lifetime_secs)); + + buildFromFile("panel_toast.xml"); + + setCanDrag(FALSE); + + mWrapperPanel = getChild("wrapper_panel"); + + setBackgroundOpaque(TRUE); // *TODO: obsolete + updateTransparency(); + + if(p.panel()) + { + insertPanel(p.panel); + } + + if(mHideBtnEnabled) + { + mHideBtn = getChild("hide_btn"); + mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); + } + + // init callbacks if present + if(!p.on_delete_toast().empty()) + { + mOnDeleteToastSignal.connect(p.on_delete_toast()); + } + + if (isModal()) + { + sModalToastsList.push_front(this); + } } void LLToast::reshape(S32 width, S32 height, BOOL called_from_parent) { - // We shouldn't use reshape from LLModalDialog since it changes toasts position. - // Toasts position should be controlled only by toast screen channel, see LLScreenChannelBase. - // see EXT-8044 - LLFloater::reshape(width, height, called_from_parent); + // We shouldn't use reshape from LLModalDialog since it changes toasts position. + // Toasts position should be controlled only by toast screen channel, see LLScreenChannelBase. + // see EXT-8044 + LLFloater::reshape(width, height, called_from_parent); } //-------------------------------------------------------------------------- BOOL LLToast::postBuild() { - if(!mCanFade) - { - mTimer->stop(); - } + if(!mCanFade) + { + mTimer->stop(); + } - return TRUE; + return TRUE; } //-------------------------------------------------------------------------- void LLToast::setHideButtonEnabled(bool enabled) { - if(mHideBtn) - mHideBtn->setEnabled(enabled); + if(mHideBtn) + mHideBtn->setEnabled(enabled); } //-------------------------------------------------------------------------- LLToast::~LLToast() { - if(LLApp::isQuitting()) - { - mOnFadeSignal.disconnect_all_slots(); - mOnDeleteToastSignal.disconnect_all_slots(); - mOnToastDestroyedSignal.disconnect_all_slots(); - mOnToastHoverSignal.disconnect_all_slots(); - mToastMouseEnterSignal.disconnect_all_slots(); - mToastMouseLeaveSignal.disconnect_all_slots(); - } - else - { - mOnToastDestroyedSignal(this); - } - - if (isModal()) - { - std::list::iterator iter = std::find(sModalToastsList.begin(), sModalToastsList.end(), this); - if (iter != sModalToastsList.end()) - { - sModalToastsList.erase(iter); - } - } + if(LLApp::isQuitting()) + { + mOnFadeSignal.disconnect_all_slots(); + mOnDeleteToastSignal.disconnect_all_slots(); + mOnToastDestroyedSignal.disconnect_all_slots(); + mOnToastHoverSignal.disconnect_all_slots(); + mToastMouseEnterSignal.disconnect_all_slots(); + mToastMouseLeaveSignal.disconnect_all_slots(); + } + else + { + mOnToastDestroyedSignal(this); + } + + if (isModal()) + { + std::list::iterator iter = std::find(sModalToastsList.begin(), sModalToastsList.end(), this); + if (iter != sModalToastsList.end()) + { + sModalToastsList.erase(iter); + } + } } //-------------------------------------------------------------------------- void LLToast::hide() { - if (!mIsHidden) - { - setVisible(FALSE); - setFading(false); - mTimer->stop(); - mIsHidden = true; - mOnFadeSignal(this); - } + if (!mIsHidden) + { + setVisible(FALSE); + setFading(false); + mTimer->stop(); + mIsHidden = true; + mOnFadeSignal(this); + } } /*virtual*/ @@ -227,188 +227,188 @@ void LLToast::setFocus(BOOL b) void LLToast::onFocusLost() { - if(mWrapperPanel && !isBackgroundVisible()) - { - // Lets make wrapper panel behave like a floater - updateTransparency(); - } + if(mWrapperPanel && !isBackgroundVisible()) + { + // Lets make wrapper panel behave like a floater + updateTransparency(); + } } void LLToast::onFocusReceived() { - if(mWrapperPanel && !isBackgroundVisible()) - { - // Lets make wrapper panel behave like a floater - updateTransparency(); - } + if(mWrapperPanel && !isBackgroundVisible()) + { + // Lets make wrapper panel behave like a floater + updateTransparency(); + } } void LLToast::setLifetime(S32 seconds) { - mToastLifetime = seconds; + mToastLifetime = seconds; } void LLToast::setFadingTime(S32 seconds) { - mToastFadingTime = seconds; + mToastFadingTime = seconds; } void LLToast::closeToast() { - mOnDeleteToastSignal(this); + mOnDeleteToastSignal(this); - setSoundFlags(SILENT); + setSoundFlags(SILENT); - closeFloater(); + closeFloater(); } S32 LLToast::getTopPad() { - if(mWrapperPanel) - { - return getRect().getHeight() - mWrapperPanel->getRect().getHeight(); - } - return 0; + if(mWrapperPanel) + { + return getRect().getHeight() - mWrapperPanel->getRect().getHeight(); + } + return 0; } S32 LLToast::getRightPad() { - if(mWrapperPanel) - { - return getRect().getWidth() - mWrapperPanel->getRect().getWidth(); - } - return 0; + if(mWrapperPanel) + { + return getRect().getWidth() - mWrapperPanel->getRect().getWidth(); + } + return 0; } //-------------------------------------------------------------------------- -void LLToast::setCanFade(bool can_fade) -{ - mCanFade = can_fade; - if(!mCanFade) - { - mTimer->stop(); - } +void LLToast::setCanFade(bool can_fade) +{ + mCanFade = can_fade; + if(!mCanFade) + { + mTimer->stop(); + } } //-------------------------------------------------------------------------- void LLToast::expire() { - if (mCanFade) - { - if (mIsFading) - { - // Fade timer expired. Time to hide. - hide(); - } - else - { - // "Life" time has ended. Time to fade. - setFading(true); - mTimer->restart(); - } - } + if (mCanFade) + { + if (mIsFading) + { + // Fade timer expired. Time to hide. + hide(); + } + else + { + // "Life" time has ended. Time to fade. + setFading(true); + mTimer->restart(); + } + } } void LLToast::setFading(bool transparent) { - mIsFading = transparent; - updateTransparency(); + mIsFading = transparent; + updateTransparency(); - if (transparent) - { - mTimer->setPeriod(mToastFadingTime); - } - else - { - mTimer->setPeriod(mToastLifetime); - } + if (transparent) + { + mTimer->setPeriod(mToastFadingTime); + } + else + { + mTimer->setPeriod(mToastLifetime); + } } F32 LLToast::getTimeLeftToLive() { - F32 time_to_live = mTimer->getRemaining(); + F32 time_to_live = mTimer->getRemaining(); - if (!mIsFading) - { - time_to_live += mToastFadingTime; - } + if (!mIsFading) + { + time_to_live += mToastFadingTime; + } - return time_to_live; + return time_to_live; } //-------------------------------------------------------------------------- void LLToast::reshapeToPanel() { - LLPanel* panel = getPanel(); - if(!panel) - return; + LLPanel* panel = getPanel(); + if(!panel) + return; - LLRect panel_rect = panel->getLocalRect(); - panel->setShape(panel_rect); - - LLRect toast_rect = getRect(); + LLRect panel_rect = panel->getLocalRect(); + panel->setShape(panel_rect); - toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, - panel_rect.getWidth() + getRightPad(), panel_rect.getHeight() + getTopPad()); - setShape(toast_rect); + LLRect toast_rect = getRect(); + + toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, + panel_rect.getWidth() + getRightPad(), panel_rect.getHeight() + getTopPad()); + setShape(toast_rect); } void LLToast::insertPanel(LLPanel* panel) { - mPanel = panel; - mWrapperPanel->addChild(panel); - reshapeToPanel(); + mPanel = panel; + mWrapperPanel->addChild(panel); + reshapeToPanel(); } //-------------------------------------------------------------------------- void LLToast::draw() { - LLFloater::draw(); - - if(!isBackgroundVisible()) - { - // Floater background is invisible, lets make wrapper panel look like a - // floater - draw shadow. - drawShadow(mWrapperPanel); + LLFloater::draw(); - // Shadow will probably overlap close button, lets redraw the button - if(mHideBtn) - { - drawChild(mHideBtn); - } - } + if(!isBackgroundVisible()) + { + // Floater background is invisible, lets make wrapper panel look like a + // floater - draw shadow. + drawShadow(mWrapperPanel); + + // Shadow will probably overlap close button, lets redraw the button + if(mHideBtn) + { + drawChild(mHideBtn); + } + } } //-------------------------------------------------------------------------- void LLToast::setVisible(BOOL show) { - if(mIsHidden) - { - // this toast is invisible after fade until its ScreenChannel will allow it - // - // (EXT-1849) according to this bug a toast can be resurrected from - // invisible state if it faded during a teleportation - // then it fades a second time and causes a crash - return; - } - - if (show && getVisible()) - { - return; - } - - if(show) - { - if(!mTimer->getStarted() && mCanFade) - { - mTimer->start(); - } - } - else - { - //hide "hide" button in case toast was hidden without mouse_leave - if(mHideBtn) - mHideBtn->setVisible(show); + if(mIsHidden) + { + // this toast is invisible after fade until its ScreenChannel will allow it + // + // (EXT-1849) according to this bug a toast can be resurrected from + // invisible state if it faded during a teleportation + // then it fades a second time and causes a crash + return; + } + + if (show && getVisible()) + { + return; + } + + if(show) + { + if(!mTimer->getStarted() && mCanFade) + { + mTimer->start(); + } + } + else + { + //hide "hide" button in case toast was hidden without mouse_leave + if(mHideBtn) + mHideBtn->setVisible(show); } LLFloater::setVisible(show); if (mPanel @@ -425,198 +425,198 @@ void LLToast::setVisible(BOOL show) void LLToast::updateHoveredState() { - S32 x, y; - LLUI::getInstance()->getMousePositionScreen(&x, &y); - - LLRect panel_rc = mWrapperPanel->calcScreenRect(); - LLRect button_rc; - if(mHideBtn) - { - button_rc = mHideBtn->calcScreenRect(); - } - - if (!panel_rc.pointInRect(x, y) && !button_rc.pointInRect(x, y)) - { - // mouse is not over this toast - mIsHovered = false; - } - else - { - bool is_overlapped_by_other_floater = false; - - const child_list_t* child_list = gFloaterView->getChildList(); - - // find this toast in gFloaterView child list to check whether any floater - // with higher Z-order is visible under the mouse pointer overlapping this toast - child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this); - if (r_iter != child_list->rend()) - { - // skip this toast and proceed to views above in Z-order - for (++r_iter; r_iter != child_list->rend(); ++r_iter) - { - LLView* view = *r_iter; - is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y); - if (is_overlapped_by_other_floater) - { - break; - } - } - } - - mIsHovered = !is_overlapped_by_other_floater; - } - - LLToastLifeTimer* timer = getTimer(); - - if (timer) - { - // Started timer means the mouse had left the toast previously. - // If toast is hovered in the current frame we should handle - // a mouse enter event. - if(timer->getStarted() && mIsHovered) - { - mOnToastHoverSignal(this, MOUSE_ENTER); - - updateTransparency(); - - //toasts fading is management by Screen Channel - - sendChildToFront(mHideBtn); - if(mHideBtn && mHideBtn->getEnabled()) - { - mHideBtn->setVisible(TRUE); - } - - mToastMouseEnterSignal(this, getValue()); - } - // Stopped timer means the mouse had entered the toast previously. - // If the toast is not hovered in the current frame we should handle - // a mouse leave event. - else if(!timer->getStarted() && !mIsHovered) - { - mOnToastHoverSignal(this, MOUSE_LEAVE); - - updateTransparency(); - - //toasts fading is management by Screen Channel - - if(mHideBtn && mHideBtn->getEnabled()) - { - if( mHideBtnPressed ) - { - mHideBtnPressed = false; - return; - } - mHideBtn->setVisible(FALSE); - } - - mToastMouseLeaveSignal(this, getValue()); - } - } + S32 x, y; + LLUI::getInstance()->getMousePositionScreen(&x, &y); + + LLRect panel_rc = mWrapperPanel->calcScreenRect(); + LLRect button_rc; + if(mHideBtn) + { + button_rc = mHideBtn->calcScreenRect(); + } + + if (!panel_rc.pointInRect(x, y) && !button_rc.pointInRect(x, y)) + { + // mouse is not over this toast + mIsHovered = false; + } + else + { + bool is_overlapped_by_other_floater = false; + + const child_list_t* child_list = gFloaterView->getChildList(); + + // find this toast in gFloaterView child list to check whether any floater + // with higher Z-order is visible under the mouse pointer overlapping this toast + child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this); + if (r_iter != child_list->rend()) + { + // skip this toast and proceed to views above in Z-order + for (++r_iter; r_iter != child_list->rend(); ++r_iter) + { + LLView* view = *r_iter; + is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y); + if (is_overlapped_by_other_floater) + { + break; + } + } + } + + mIsHovered = !is_overlapped_by_other_floater; + } + + LLToastLifeTimer* timer = getTimer(); + + if (timer) + { + // Started timer means the mouse had left the toast previously. + // If toast is hovered in the current frame we should handle + // a mouse enter event. + if(timer->getStarted() && mIsHovered) + { + mOnToastHoverSignal(this, MOUSE_ENTER); + + updateTransparency(); + + //toasts fading is management by Screen Channel + + sendChildToFront(mHideBtn); + if(mHideBtn && mHideBtn->getEnabled()) + { + mHideBtn->setVisible(TRUE); + } + + mToastMouseEnterSignal(this, getValue()); + } + // Stopped timer means the mouse had entered the toast previously. + // If the toast is not hovered in the current frame we should handle + // a mouse leave event. + else if(!timer->getStarted() && !mIsHovered) + { + mOnToastHoverSignal(this, MOUSE_LEAVE); + + updateTransparency(); + + //toasts fading is management by Screen Channel + + if(mHideBtn && mHideBtn->getEnabled()) + { + if( mHideBtnPressed ) + { + mHideBtnPressed = false; + return; + } + mHideBtn->setVisible(FALSE); + } + + mToastMouseLeaveSignal(this, getValue()); + } + } } void LLToast::setBackgroundOpaque(BOOL b) { - if(mWrapperPanel && !isBackgroundVisible()) - { - mWrapperPanel->setBackgroundOpaque(b); - } - else - { - LLModalDialog::setBackgroundOpaque(b); - } + if(mWrapperPanel && !isBackgroundVisible()) + { + mWrapperPanel->setBackgroundOpaque(b); + } + else + { + LLModalDialog::setBackgroundOpaque(b); + } } void LLToast::updateTransparency() { - ETypeTransparency transparency_type; - - if (mCanFade) - { - // Notification toasts (including IM/chat toasts) change their transparency on hover. - if (isHovered()) - { - transparency_type = TT_ACTIVE; - } - else - { - transparency_type = mIsFading ? TT_FADING : TT_INACTIVE; - } - } - else - { - // Transparency of alert toasts depends on focus. - transparency_type = hasFocus() ? TT_ACTIVE : TT_INACTIVE; - } - - LLFloater::updateTransparency(transparency_type); + ETypeTransparency transparency_type; + + if (mCanFade) + { + // Notification toasts (including IM/chat toasts) change their transparency on hover. + if (isHovered()) + { + transparency_type = TT_ACTIVE; + } + else + { + transparency_type = mIsFading ? TT_FADING : TT_INACTIVE; + } + } + else + { + // Transparency of alert toasts depends on focus. + transparency_type = hasFocus() ? TT_ACTIVE : TT_INACTIVE; + } + + LLFloater::updateTransparency(transparency_type); } void LLNotificationsUI::LLToast::stopTimer() { - if(mCanFade) - { - setFading(false); - mTimer->stop(); - } + if(mCanFade) + { + setFading(false); + mTimer->stop(); + } } void LLNotificationsUI::LLToast::startTimer() { - if(mCanFade) - { - setFading(false); - mTimer->start(); - } + if(mCanFade) + { + setFading(false); + mTimer->start(); + } } //-------------------------------------------------------------------------- BOOL LLToast::handleMouseDown(S32 x, S32 y, MASK mask) { - if(mHideBtn && mHideBtn->getEnabled()) - { - mHideBtnPressed = mHideBtn->getRect().pointInRect(x, y); - } + if(mHideBtn && mHideBtn->getEnabled()) + { + mHideBtnPressed = mHideBtn->getRect().pointInRect(x, y); + } - return LLModalDialog::handleMouseDown(x, y, mask); + return LLModalDialog::handleMouseDown(x, y, mask); } //-------------------------------------------------------------------------- bool LLToast::isNotificationValid() { - if(mNotification) - { - return !mNotification->isCancelled(); - } - return false; + if(mNotification) + { + return !mNotification->isCancelled(); + } + return false; } //-------------------------------------------------------------------------- -S32 LLToast::notifyParent(const LLSD& info) +S32 LLToast::notifyParent(const LLSD& info) { - if (info.has("action") && "hide_toast" == info["action"].asString()) - { - hide(); - return 1; - } + if (info.has("action") && "hide_toast" == info["action"].asString()) + { + hide(); + return 1; + } - return LLModalDialog::notifyParent(info); + return LLModalDialog::notifyParent(info); } //static void LLToast::updateClass() { - for (auto& toast : LLInstanceTracker::instance_snapshot()) - { - toast.updateHoveredState(); - } + for (auto& toast : LLInstanceTracker::instance_snapshot()) + { + toast.updateHoveredState(); + } } -// static +// static void LLToast::cleanupToasts() { - LLInstanceTracker::instance_snapshot().deleteAll(); + LLInstanceTracker::instance_snapshot().deleteAll(); } diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 49969ab70a..460317aaa9 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -1,25 +1,25 @@ -/** +/** * @file lltoast.h * @brief This class implements a placeholder for any notification panel. * * $LicenseInfo:firstyear=2003&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$ */ @@ -50,18 +50,18 @@ class LLToast; class LLToastLifeTimer: public LLEventTimer { public: - LLToastLifeTimer(LLToast* toast, F32 period); + LLToastLifeTimer(LLToast* toast, F32 period); - /*virtual*/ - bool tick() override; - void restart(); - bool getStarted(); - void setPeriod(F32 period); -// F32 getRemainingTimeF32(); + /*virtual*/ + bool tick() override; + void restart(); + bool getStarted(); + void setPeriod(F32 period); +// F32 getRemainingTimeF32(); -// LLTimer& getEventTimer() { return mEventTimer;} +// LLTimer& getEventTimer() { return mEventTimer;} private : - LLToast* mToast; + LLToast* mToast; }; /** @@ -70,184 +70,184 @@ private : */ class LLToast : public LLModalDialog, public LLInstanceTracker { - friend class LLToastLifeTimer; + friend class LLToastLifeTimer; public: - typedef boost::function toast_callback_t; - typedef boost::signals2::signal toast_signal_t; - typedef boost::signals2::signal toast_hover_check_signal_t; + typedef boost::function toast_callback_t; + typedef boost::signals2::signal toast_signal_t; + typedef boost::signals2::signal toast_hover_check_signal_t; + + struct Params : public LLInitParam::Block + { + Mandatory panel; + Optional notif_id, //notification ID + session_id; //im session ID + Optional notification; - struct Params : public LLInitParam::Block - { - Mandatory panel; - Optional notif_id, //notification ID - session_id; //im session ID - Optional notification; + //NOTE: Life time of a toast (i.e. period of time from the moment toast was shown + //till the moment when toast was hidden) is the sum of lifetime_secs and fading_time_secs. - //NOTE: Life time of a toast (i.e. period of time from the moment toast was shown - //till the moment when toast was hidden) is the sum of lifetime_secs and fading_time_secs. + Optional lifetime_secs, // Number of seconds while a toast is non-transparent + fading_time_secs; // Number of seconds while a toast is transparent - Optional lifetime_secs, // Number of seconds while a toast is non-transparent - fading_time_secs; // Number of seconds while a toast is transparent + Optional on_delete_toast; + Optional can_fade, + can_be_stored, + enable_hide_btn, + is_modal, + is_tip, + force_show, + force_store; - Optional on_delete_toast; - Optional can_fade, - can_be_stored, - enable_hide_btn, - is_modal, - is_tip, - force_show, - force_store; + Params(); + }; - Params(); - }; - - static void updateClass(); - static void cleanupToasts(); + static void updateClass(); + static void cleanupToasts(); - static BOOL isAlertToastShown() { return sModalToastsList.size() > 0; } + static BOOL isAlertToastShown() { return sModalToastsList.size() > 0; } - LLToast(const LLToast::Params& p); - virtual ~LLToast(); - BOOL postBuild(); + LLToast(const LLToast::Params& p); + virtual ~LLToast(); + BOOL postBuild(); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - // Toast handlers - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + // Toast handlers + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - //Fading + //Fading - /** Stop lifetime/fading timer */ - virtual void stopTimer(); + /** Stop lifetime/fading timer */ + virtual void stopTimer(); - /** Start lifetime/fading timer */ - virtual void startTimer(); + /** Start lifetime/fading timer */ + virtual void startTimer(); - bool isHovered() { return mIsHovered; } + bool isHovered() { return mIsHovered; } - // Operating with toasts - // insert a panel to a toast - void insertPanel(LLPanel* panel); + // Operating with toasts + // insert a panel to a toast + void insertPanel(LLPanel* panel); - void reshapeToPanel(); + void reshapeToPanel(); - // get toast's panel - LLPanel* getPanel() const { return mPanel; } - // enable/disable Toast's Hide button - void setHideButtonEnabled(bool enabled); - // - F32 getTimeLeftToLive(); - // - LLToastLifeTimer* getTimer() { return mTimer.get();} - // - virtual void draw(); - // - virtual void setVisible(BOOL show); + // get toast's panel + LLPanel* getPanel() const { return mPanel; } + // enable/disable Toast's Hide button + void setHideButtonEnabled(bool enabled); + // + F32 getTimeLeftToLive(); + // + LLToastLifeTimer* getTimer() { return mTimer.get();} + // + virtual void draw(); + // + virtual void setVisible(BOOL show); - /*virtual*/ void setBackgroundOpaque(BOOL b); - // - virtual void hide(); + /*virtual*/ void setBackgroundOpaque(BOOL b); + // + virtual void hide(); - /*virtual*/ void setFocus(BOOL b); + /*virtual*/ void setFocus(BOOL b); - /*virtual*/ void onFocusLost(); + /*virtual*/ void onFocusLost(); - /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusReceived(); - void setLifetime(S32 seconds); + void setLifetime(S32 seconds); - void setFadingTime(S32 seconds); + void setFadingTime(S32 seconds); - void closeToast(); + void closeToast(); - /** - * Returns padding between floater top and wrapper_panel top. - * This padding should be taken into account when positioning or reshaping toasts - */ - S32 getTopPad(); + /** + * Returns padding between floater top and wrapper_panel top. + * This padding should be taken into account when positioning or reshaping toasts + */ + S32 getTopPad(); - S32 getRightPad(); + S32 getRightPad(); - // get/set Toast's flags or states - // get information whether the notification corresponding to the toast is valid or not - bool isNotificationValid(); + // get/set Toast's flags or states + // get information whether the notification corresponding to the toast is valid or not + bool isNotificationValid(); - // get toast's Notification ID - const LLUUID getNotificationID() const { return mNotificationID;} - // get toast's Session ID - const LLUUID getSessionID() const { return mSessionID;} - // - void setCanFade(bool can_fade); - // - void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } - // - bool getCanBeStored() { return mCanBeStored; } - // set whether this toast considered as hidden or not - void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; } + // get toast's Notification ID + const LLUUID getNotificationID() const { return mNotificationID;} + // get toast's Session ID + const LLUUID getSessionID() const { return mSessionID;} + // + void setCanFade(bool can_fade); + // + void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } + // + bool getCanBeStored() { return mCanBeStored; } + // set whether this toast considered as hidden or not + void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; } - const LLNotificationPtr& getNotification() const { return mNotification;} + const LLNotificationPtr& getNotification() const { return mNotification;} - // Registers signals/callbacks for events - boost::signals2::connection setOnFadeCallback(const toast_signal_t::slot_type& cb) { return mOnFadeSignal.connect(cb); } - boost::signals2::connection setOnToastDestroyedCallback(const toast_signal_t::slot_type& cb) { return mOnToastDestroyedSignal.connect(cb); } - boost::signals2::connection setOnToastHoverCallback(const toast_hover_check_signal_t::slot_type& cb) { return mOnToastHoverSignal.connect(cb); } + // Registers signals/callbacks for events + boost::signals2::connection setOnFadeCallback(const toast_signal_t::slot_type& cb) { return mOnFadeSignal.connect(cb); } + boost::signals2::connection setOnToastDestroyedCallback(const toast_signal_t::slot_type& cb) { return mOnToastDestroyedSignal.connect(cb); } + boost::signals2::connection setOnToastHoverCallback(const toast_hover_check_signal_t::slot_type& cb) { return mOnToastHoverSignal.connect(cb); } - boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseEnterSignal.connect(cb); }; - boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseLeaveSignal.connect(cb); }; + boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseEnterSignal.connect(cb); }; + boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) { return mToastMouseLeaveSignal.connect(cb); }; - virtual S32 notifyParent(const LLSD& info); + virtual S32 notifyParent(const LLSD& info); - LLHandle getHandle() const { return getDerivedHandle(); } + LLHandle getHandle() const { return getDerivedHandle(); } protected: - void updateTransparency(); + void updateTransparency(); private: - void updateHoveredState(); + void updateHoveredState(); + + void expire(); + + void setFading(bool fading); - void expire(); + LLUUID mNotificationID; + LLUUID mSessionID; + LLNotificationPtr mNotification; - void setFading(bool fading); + //LLRootHandle mHandle; - LLUUID mNotificationID; - LLUUID mSessionID; - LLNotificationPtr mNotification; + LLPanel* mWrapperPanel; - //LLRootHandle mHandle; - - LLPanel* mWrapperPanel; + // timer counts a lifetime of a toast + std::unique_ptr mTimer; - // timer counts a lifetime of a toast - std::unique_ptr mTimer; + F32 mToastLifetime; // in seconds + F32 mToastFadingTime; // in seconds - F32 mToastLifetime; // in seconds - F32 mToastFadingTime; // in seconds - - LLPanel* mPanel; - LLButton* mHideBtn; + LLPanel* mPanel; + LLButton* mHideBtn; - LLColor4 mBgColor; - bool mCanFade; - bool mCanBeStored; - bool mHideBtnEnabled; - bool mHideBtnPressed; - bool mIsHidden; // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849) - bool mIsTip; - bool mIsFading; - bool mIsHovered; + LLColor4 mBgColor; + bool mCanFade; + bool mCanBeStored; + bool mHideBtnEnabled; + bool mHideBtnPressed; + bool mIsHidden; // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849) + bool mIsTip; + bool mIsFading; + bool mIsHovered; - toast_signal_t mOnFadeSignal; - toast_signal_t mOnDeleteToastSignal; - toast_signal_t mOnToastDestroyedSignal; - toast_hover_check_signal_t mOnToastHoverSignal; + toast_signal_t mOnFadeSignal; + toast_signal_t mOnDeleteToastSignal; + toast_signal_t mOnToastDestroyedSignal; + toast_hover_check_signal_t mOnToastHoverSignal; - commit_signal_t mToastMouseEnterSignal; - commit_signal_t mToastMouseLeaveSignal; + commit_signal_t mToastMouseEnterSignal; + commit_signal_t mToastMouseLeaveSignal; - static std::list sModalToastsList; + static std::list sModalToastsList; }; } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index a4e6d20181..94aa4a61ac 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltoolplacer.cpp * @brief Tool for placing new objects into the world * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -60,480 +60,480 @@ // linden library headers #include "llprimitive.h" -#include "llwindow.h" // incBusyCount() +#include "llwindow.h" // incBusyCount() #include "material_codes.h" #include "lluiusage.h" const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f); -//static -LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; +//static +LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; LLToolPlacer::LLToolPlacer() -: LLTool( "Create" ) +: LLTool( "Create" ) { } -BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, - BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) +BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, + BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) { - F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; - - // Viewer-side pick to find the right sim to create the object on. - // First find the surface the object will be created on. - LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); - - // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok - // representations (if any) are NOT the same as their viewer representation. - if (pick.mPickType == LLPickInfo::PICK_FLORA) - { - *hit_obj = NULL; - *hit_face = -1; - } - else - { - *hit_obj = pick.getObject(); - *hit_face = pick.mObjectFace; - } - *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); - LLVector3d land_pos_global = pick.mPosGlobal; - - // Make sure there's a surface to place the new object on. - BOOL bypass_sim_raycast = FALSE; - LLVector3d surface_pos_global; - if (*b_hit_land) - { - surface_pos_global = land_pos_global; - bypass_sim_raycast = TRUE; - } - else - if (*hit_obj) - { - surface_pos_global = (*hit_obj)->getPositionGlobal(); - } - else - { - return FALSE; - } - - // Make sure the surface isn't too far away. - LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); - F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); - if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) - { - return FALSE; - } - - // Find the sim where the surface lives. - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); - if (!regionp) - { - LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; - return FALSE; - } - - // Find the simulator-side ray that will be used to place the object accurately - LLVector3d mouse_direction; - mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); - - *region = regionp; - *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); - F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. - *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; - - if( bypass_sim_raycast ) - { - // Hack to work around Havok's inability to ray cast onto height fields - *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point - } - else - { - LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. - *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); - } - - return TRUE; + F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; + + // Viewer-side pick to find the right sim to create the object on. + // First find the surface the object will be created on. + LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); + + // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok + // representations (if any) are NOT the same as their viewer representation. + if (pick.mPickType == LLPickInfo::PICK_FLORA) + { + *hit_obj = NULL; + *hit_face = -1; + } + else + { + *hit_obj = pick.getObject(); + *hit_face = pick.mObjectFace; + } + *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); + LLVector3d land_pos_global = pick.mPosGlobal; + + // Make sure there's a surface to place the new object on. + BOOL bypass_sim_raycast = FALSE; + LLVector3d surface_pos_global; + if (*b_hit_land) + { + surface_pos_global = land_pos_global; + bypass_sim_raycast = TRUE; + } + else + if (*hit_obj) + { + surface_pos_global = (*hit_obj)->getPositionGlobal(); + } + else + { + return FALSE; + } + + // Make sure the surface isn't too far away. + LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); + F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); + if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) + { + return FALSE; + } + + // Find the sim where the surface lives. + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); + if (!regionp) + { + LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; + return FALSE; + } + + // Find the simulator-side ray that will be used to place the object accurately + LLVector3d mouse_direction; + mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); + + *region = regionp; + *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); + F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. + *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; + + if( bypass_sim_raycast ) + { + // Hack to work around Havok's inability to ray cast onto height fields + *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point + } + else + { + LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. + *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); + } + + return TRUE; } BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - BOOL b_hit_land = FALSE; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - return FALSE; - } + LLVector3 ray_start_region; + LLVector3 ray_end_region; + LLViewerRegion* regionp = NULL; + BOOL b_hit_land = FALSE; + S32 hit_face = -1; + LLViewerObject* hit_obj = NULL; + BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); + if( !success ) + { + return FALSE; + } return rezNewObject(pcode,hit_obj, hit_face, b_hit_land, ray_start_region, ray_end_region, regionp, use_physics); } BOOL LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion* regionp, U8 use_physics) { - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - return FALSE; - } - - if (NULL == regionp) - { - LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; - return FALSE; - } - - if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) - { - //LLFirstUse::useSandbox(); - } - - // Set params for new object based on its PCode. - LLQuaternion rotation; - LLVector3 scale = DEFAULT_OBJECT_SCALE; - U8 material = LL_MCODE_WOOD; - BOOL create_selected = FALSE; - LLVolumeParams volume_params; + if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) + { + // Can't create objects on avatars or attachments + return FALSE; + } + + if (NULL == regionp) + { + LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; + return FALSE; + } + + if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) + { + //LLFirstUse::useSandbox(); + } + + // Set params for new object based on its PCode. + LLQuaternion rotation; + LLVector3 scale = DEFAULT_OBJECT_SCALE; + U8 material = LL_MCODE_WOOD; + BOOL create_selected = FALSE; + LLVolumeParams volume_params; U8 state = 0; - - switch (pcode) - { - case LL_PCODE_LEGACY_GRASS: - // Randomize size of grass patch - scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); - state = rand() % LLVOGrass::sMaxGrassSpecies; - break; - - - case LL_PCODE_LEGACY_TREE: - case LL_PCODE_TREE_NEW: - state = rand() % LLVOTree::sMaxTreeSpecies; - break; - - case LL_PCODE_SPHERE: - case LL_PCODE_CONE: - case LL_PCODE_CUBE: - case LL_PCODE_CYLINDER: - case LL_PCODE_TORUS: - case LLViewerObject::LL_VO_SQUARE_TORUS: - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - default: - create_selected = TRUE; - break; - } - - // Play creation sound - if (gAudiop) - { - gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), - gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - } - - LLUIUsage::instance().logCommand("Build.ObjectAdd"); - gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU8Fast(_PREHASH_Material, material); - - U32 flags = 0; // not selected - if (use_physics) - { - flags |= FLAGS_USE_PHYSICS; - } - if (create_selected) - { - flags |= FLAGS_CREATE_SELECTED; - } - gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); - - LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error - switch (pcode) - { - case LL_PCODE_SPHERE: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_SQUARE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_SPHERE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - //volume_params.setBeginAndEndS( 0.5f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 0.5f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CUBE: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PRISM: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 1 ); - volume_params.setShear ( -0.5f, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PYRAMID: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TETRAHEDRON: - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - default: - LLVolumeMessage::packVolumeParams(0, gMessageSystem); - volume_pcode = pcode; - break; - } - gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); - - gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); - gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); - gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); - gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); - gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); - gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); - gMessageSystem->addU8Fast(_PREHASH_State, state); - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); - - // Pack in name value pairs - gMessageSystem->sendReliable(regionp->getHost()); - - // Spawns a message, so must be after above send - if (create_selected) - { - LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->getWindow()->incBusyCount(); - } - - // VEFFECT: AddObject - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); - effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); - effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); - effectp->setDuration(LL_HUD_DUR_SHORT); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - - add(LLStatViewer::OBJECT_CREATE, 1); - - return TRUE; + + switch (pcode) + { + case LL_PCODE_LEGACY_GRASS: + // Randomize size of grass patch + scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); + state = rand() % LLVOGrass::sMaxGrassSpecies; + break; + + + case LL_PCODE_LEGACY_TREE: + case LL_PCODE_TREE_NEW: + state = rand() % LLVOTree::sMaxTreeSpecies; + break; + + case LL_PCODE_SPHERE: + case LL_PCODE_CONE: + case LL_PCODE_CUBE: + case LL_PCODE_CYLINDER: + case LL_PCODE_TORUS: + case LLViewerObject::LL_VO_SQUARE_TORUS: + case LLViewerObject::LL_VO_TRIANGLE_TORUS: + default: + create_selected = TRUE; + break; + } + + // Play creation sound + if (gAudiop) + { + gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), + gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); + } + + LLUIUsage::instance().logCommand("Build.ObjectAdd"); + gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU8Fast(_PREHASH_Material, material); + + U32 flags = 0; // not selected + if (use_physics) + { + flags |= FLAGS_USE_PHYSICS; + } + if (create_selected) + { + flags |= FLAGS_CREATE_SELECTED; + } + gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); + + LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error + switch (pcode) + { + case LL_PCODE_SPHERE: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LLViewerObject::LL_VO_SQUARE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LLViewerObject::LL_VO_TRIANGLE_TORUS: + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1.f, 0.25f ); // "top size" + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_SPHERE_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); + //volume_params.setBeginAndEndS( 0.5f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 0.5f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CUBE: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_PRISM: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 1 ); + volume_params.setShear ( -0.5f, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_PYRAMID: + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_TETRAHEDRON: + volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CYLINDER: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CYLINDER_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.25f, 0.75f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CONE: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + case LL_PCODE_CONE_HEMI: + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.25f, 0.75f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 0, 0 ); + volume_params.setShear ( 0, 0 ); + LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); + volume_pcode = LL_PCODE_VOLUME; + break; + + default: + LLVolumeMessage::packVolumeParams(0, gMessageSystem); + volume_pcode = pcode; + break; + } + gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); + + gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); + gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); + gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); + gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); + gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); + gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); + gMessageSystem->addU8Fast(_PREHASH_State, state); + + // Limit raycast to a single object. + // Speeds up server raycast + avoid problems with server ray hitting objects + // that were clipped by the near plane or culled on the viewer. + LLUUID ray_target_id; + if( hit_obj ) + { + ray_target_id = hit_obj->getID(); + } + else + { + ray_target_id.setNull(); + } + gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); + + // Pack in name value pairs + gMessageSystem->sendReliable(regionp->getHost()); + + // Spawns a message, so must be after above send + if (create_selected) + { + LLSelectMgr::getInstance()->deselectAll(); + gViewerWindow->getWindow()->incBusyCount(); + } + + // VEFFECT: AddObject + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); + effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); + effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + + add(LLStatViewer::OBJECT_CREATE, 1); + + return TRUE; } // Used by the placer tool to add copies of the current selection. // Inspired by add_object(). JC BOOL LLToolPlacer::addDuplicate(S32 x, S32 y) { - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - BOOL b_hit_land = FALSE; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - make_ui_sound("UISndInvalidOp"); - return FALSE; - } - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - make_ui_sound("UISndInvalidOp"); - return FALSE; - } - - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - - LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, - ray_end_region, - b_hit_land, // suppress raycast - FALSE, // intersection - ray_target_id, - gSavedSettings.getBOOL("CreateToolCopyCenters"), - gSavedSettings.getBOOL("CreateToolCopyRotates"), - FALSE); // select copy - - if (regionp - && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) - { - //LLFirstUse::useSandbox(); - } - - return TRUE; + LLVector3 ray_start_region; + LLVector3 ray_end_region; + LLViewerRegion* regionp = NULL; + BOOL b_hit_land = FALSE; + S32 hit_face = -1; + LLViewerObject* hit_obj = NULL; + BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); + if( !success ) + { + make_ui_sound("UISndInvalidOp"); + return FALSE; + } + if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) + { + // Can't create objects on avatars or attachments + make_ui_sound("UISndInvalidOp"); + return FALSE; + } + + + // Limit raycast to a single object. + // Speeds up server raycast + avoid problems with server ray hitting objects + // that were clipped by the near plane or culled on the viewer. + LLUUID ray_target_id; + if( hit_obj ) + { + ray_target_id = hit_obj->getID(); + } + else + { + ray_target_id.setNull(); + } + + LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, + ray_end_region, + b_hit_land, // suppress raycast + FALSE, // intersection + ray_target_id, + gSavedSettings.getBOOL("CreateToolCopyCenters"), + gSavedSettings.getBOOL("CreateToolCopyRotates"), + FALSE); // select copy + + if (regionp + && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) + { + //LLFirstUse::useSandbox(); + } + + return TRUE; } BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) { - BOOL added = TRUE; - - if (gSavedSettings.getBOOL("CreateToolCopySelection")) - { - added = addDuplicate(x, y); - } - else - { - added = addObject( sObjectType, x, y, FALSE ); - } - - // ...and go back to the default tool - if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) - { - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); - } - - return added; + BOOL added = TRUE; + + if (gSavedSettings.getBOOL("CreateToolCopySelection")) + { + added = addDuplicate(x, y); + } + else + { + added = addObject( sObjectType, x, y, FALSE ); + } + + // ...and go back to the default tool + if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) + { + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); + } + + return added; } BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask) { - LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; - gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); - return TRUE; + LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; + gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); + return TRUE; } void LLToolPlacer::handleSelect() { - gFloaterTools->setStatusText("place"); + gFloaterTools->setStatusText("place"); } void LLToolPlacer::handleDeselect() diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index d20d682710..8b56790f7d 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -1,25 +1,25 @@ -/** +/** * @file lltoolplacer.h * @brief Tool for placing new objects into the world * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,31 +37,31 @@ class LLViewerRegion; // LLToolPlacer class LLToolPlacer - : public LLTool + : public LLTool { public: - LLToolPlacer(); + LLToolPlacer(); - virtual BOOL placeObject(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual void handleSelect(); // do stuff when your tool is selected - virtual void handleDeselect(); // clean up when your tool is deselected + virtual BOOL placeObject(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual void handleSelect(); // do stuff when your tool is selected + virtual void handleDeselect(); // clean up when your tool is deselected - static void setObjectType( LLPCode type ) { sObjectType = type; } - static LLPCode getObjectType() { return sObjectType; } + static void setObjectType( LLPCode type ) { sObjectType = type; } + static LLPCode getObjectType() { return sObjectType; } static BOOL addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics); static BOOL rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, BOOL b_hit_land, LLVector3 ray_start_region, LLVector3 ray_end_region, LLViewerRegion *regionp, U8 use_physics); protected: - static LLPCode sObjectType; + static LLPCode sObjectType; private: - - static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, - BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); - BOOL addDuplicate(S32 x, S32 y); + + static BOOL raycastForNewObjPos(S32 x, S32 y, LLViewerObject **hit_obj, S32 *hit_face, + BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ); + BOOL addDuplicate(S32 x, S32 y); }; #endif diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 16c4084a77..4e39b03903 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2009-07-09 * @brief Implementation for llviewercontrollistener. - * + * * $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$ */ @@ -44,182 +44,182 @@ LLViewerControlListener sSavedSettingsListener; } // unnamed namespace LLViewerControlListener::LLViewerControlListener() - : LLEventAPI("LLViewerControl", - "LLViewerControl listener: set, toggle or set default for various controls") + : LLEventAPI("LLViewerControl", + "LLViewerControl listener: set, toggle or set default for various controls") { - std::ostringstream groupnames; - groupnames << "[\"group\"] is one of "; - const char* delim = ""; - for (const auto& key : LLControlGroup::key_snapshot()) - { - groupnames << delim << '"' << key << '"'; - delim = ", "; - } - groupnames << '\n'; - std::string grouphelp(groupnames.str()); - std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); - - add("set", - std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" - "If [\"value\"] omitted, set to control's defined default value\n") + - grouphelp + replyhelp, - &LLViewerControlListener::set, - LLSDMap("group", LLSD())("key", LLSD())); - add("toggle", - std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, - &LLViewerControlListener::toggle, - LLSDMap("group", LLSD())("key", LLSD())); - add("get", - std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + - grouphelp, - &LLViewerControlListener::get, - LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); - add("groups", - "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", - &LLViewerControlListener::groups, - LLSDMap("reply", LLSD())); - add("vars", - std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" - "each of whose entries looks like:\n" - " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, - &LLViewerControlListener::vars, - LLSDMap("group", LLSD())("reply", LLSD())); + std::ostringstream groupnames; + groupnames << "[\"group\"] is one of "; + const char* delim = ""; + for (const auto& key : LLControlGroup::key_snapshot()) + { + groupnames << delim << '"' << key << '"'; + delim = ", "; + } + groupnames << '\n'; + std::string grouphelp(groupnames.str()); + std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); + + add("set", + std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" + "If [\"value\"] omitted, set to control's defined default value\n") + + grouphelp + replyhelp, + &LLViewerControlListener::set, + LLSDMap("group", LLSD())("key", LLSD())); + add("toggle", + std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, + &LLViewerControlListener::toggle, + LLSDMap("group", LLSD())("key", LLSD())); + add("get", + std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + + grouphelp, + &LLViewerControlListener::get, + LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); + add("groups", + "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", + &LLViewerControlListener::groups, + LLSDMap("reply", LLSD())); + add("vars", + std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" + "each of whose entries looks like:\n" + " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, + &LLViewerControlListener::vars, + LLSDMap("group", LLSD())("reply", LLSD())); } struct Info { - Info(const LLSD& request): - response(LLSD(), request), - groupname(request["group"]), - group(LLControlGroup::getInstance(groupname)), - key(request["key"]), - control(NULL) - { - if (! group) - { - response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); - return; - } - - control = group->getControl(key); - if (! control) - { - response.error(STRINGIZE("In group '" << groupname - << "', unrecognized control key '" << key << "'")); - } - } - - ~Info() - { - // If in fact the request passed to our constructor names a valid - // group and key, grab the final value of the indicated control and - // stuff it in our response. Since this outer destructor runs before - // the contained Response destructor, this data will go into the - // response we send. - if (control) - { - response["name"] = control->getName(); - response["type"] = LLControlGroup::typeEnumToString(control->type()); - response["value"] = control->get(); - response["comment"] = control->getComment(); - } - } - - LLEventAPI::Response response; - std::string groupname; - LLControlGroup::ptr_t group; - std::string key; - LLControlVariable* control; + Info(const LLSD& request): + response(LLSD(), request), + groupname(request["group"]), + group(LLControlGroup::getInstance(groupname)), + key(request["key"]), + control(NULL) + { + if (! group) + { + response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); + return; + } + + control = group->getControl(key); + if (! control) + { + response.error(STRINGIZE("In group '" << groupname + << "', unrecognized control key '" << key << "'")); + } + } + + ~Info() + { + // If in fact the request passed to our constructor names a valid + // group and key, grab the final value of the indicated control and + // stuff it in our response. Since this outer destructor runs before + // the contained Response destructor, this data will go into the + // response we send. + if (control) + { + response["name"] = control->getName(); + response["type"] = LLControlGroup::typeEnumToString(control->type()); + response["value"] = control->get(); + response["comment"] = control->getComment(); + } + } + + LLEventAPI::Response response; + std::string groupname; + LLControlGroup::ptr_t group; + std::string key; + LLControlVariable* control; }; //static void LLViewerControlListener::set(LLSD const & request) { - Info info(request); - if (! info.control) - return; + Info info(request); + if (! info.control) + return; - if (request.has("value")) - { + if (request.has("value")) + { LL_WARNS("LLViewerControlListener") << "Changing debug setting " << std::quoted(info.key) << " to " << request["value"] << LL_ENDL; - info.control->setValue(request["value"], false); - } - else - { - info.control->resetToDefault(); - } + info.control->setValue(request["value"], false); + } + else + { + info.control->resetToDefault(); + } } //static void LLViewerControlListener::toggle(LLSD const & request) { - Info info(request); - if (! info.control) - return; + Info info(request); + if (! info.control) + return; - if (info.control->isType(TYPE_BOOLEAN)) - { + if (info.control->isType(TYPE_BOOLEAN)) + { bool value = !info.control->get().asBoolean(); LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << " to " << value << LL_ENDL; info.control->set(value, false); - } - else - { - info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname - << "' control '" << info.key - << "', type is " - << LLControlGroup::typeEnumToString(info.control->type()))); - } + } + else + { + info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname + << "' control '" << info.key + << "', type is " + << LLControlGroup::typeEnumToString(info.control->type()))); + } } void LLViewerControlListener::get(LLSD const & request) { - // The Info constructor and destructor actually do all the work here. - Info info(request); + // The Info constructor and destructor actually do all the work here. + Info info(request); } void LLViewerControlListener::groups(LLSD const & request) { - // No Info, we're not looking up either a group or a control name. - Response response(LLSD(), request); - for (const auto& key : LLControlGroup::key_snapshot()) - { - response["groups"].append(key); - } + // No Info, we're not looking up either a group or a control name. + Response response(LLSD(), request); + for (const auto& key : LLControlGroup::key_snapshot()) + { + response["groups"].append(key); + } } struct CollectVars: public LLControlGroup::ApplyFunctor { - CollectVars(LLControlGroup::ptr_t g): - mGroup(g) - {} - - virtual void apply(const std::string& name, LLControlVariable* control) - { - vars.append(LLSDMap - ("name", name) - ("type", LLControlGroup::typeEnumToString(control->type())) - ("value", control->get()) - ("comment", control->getComment())); - } - - LLControlGroup::ptr_t mGroup; - LLSD vars; + CollectVars(LLControlGroup::ptr_t g): + mGroup(g) + {} + + virtual void apply(const std::string& name, LLControlVariable* control) + { + vars.append(LLSDMap + ("name", name) + ("type", LLControlGroup::typeEnumToString(control->type())) + ("value", control->get()) + ("comment", control->getComment())); + } + + LLControlGroup::ptr_t mGroup; + LLSD vars; }; void LLViewerControlListener::vars(LLSD const & request) { - // This method doesn't use Info, because we're not looking up a specific - // control name. - Response response(LLSD(), request); - std::string groupname(request["group"]); - auto group(LLControlGroup::getInstance(groupname)); - if (! group) - { - return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); - } - - CollectVars collector(group); - group->applyToAll(&collector); - response["vars"] = collector.vars; + // This method doesn't use Info, because we're not looking up a specific + // control name. + Response response(LLSD(), request); + std::string groupname(request["group"]); + auto group(LLControlGroup::getInstance(groupname)); + if (! group) + { + return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); + } + + CollectVars collector(group); + group->applyToAll(&collector); + response["vars"] = collector.vars; } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 60add691c5..67da34e071 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerfloaterreg.cpp * @brief LLViewerFloaterReg class registers floaters used in the viewer * * $LicenseInfo:firstyear=2007&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$ */ @@ -182,8 +182,8 @@ const std::string FLOATER_PROFILE("profile"); class LLFloaterOpenHandler : public LLCommandHandler { public: - // requires trusted browser to trigger or an explicit click - LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } + // requires trusted browser to trigger or an explicit click + LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } bool canHandleUntrusted( const LLSD& params, @@ -195,7 +195,7 @@ public: { return true; // will fail silently } - + std::string fl_name = params[0].asString(); // External browsers explicitly ask user about opening links @@ -282,237 +282,237 @@ public: return true; } - bool handle( + bool handle( const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) override - { - if (params.size() != 1) - { - return false; - } + { + if (params.size() != 1) + { + return false; + } - const std::string floater_name = LLURI::unescape(params[0].asString()); + const std::string floater_name = LLURI::unescape(params[0].asString()); LLSD key; if (floater_name == FLOATER_PROFILE) { key["id"] = gAgentID; } - LLFloaterReg::showInstance(floater_name, key); + LLFloaterReg::showInstance(floater_name, key); - return true; - } + return true; + } }; LLFloaterOpenHandler gFloaterOpenHandler; void LLViewerFloaterReg::registerFloaters() { - if (gNonInteractive) - { - return; - } - // *NOTE: Please keep these alphabetized for easier merges - - LLFloaterAboutUtil::registerFloater(); - LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build); - LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); - LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); - LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + if (gNonInteractive) + { + return; + } + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterAboutUtil::registerFloater(); + LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("ban_duration", "floater_ban_duration.xml", &LLFloaterReg::build); + LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); + LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); + LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("change_item_thumbnail", "floater_change_item_thumbnail.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); - LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("edit_hover_height", "floater_edit_hover_height.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); + LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("edit_hover_height", "floater_edit_hover_height.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inventory_thumbnails_helper", "floater_inventory_thumbnails_helper.xml", (LLFloaterBuildFunc) &LLFloaterReg::build); - LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLInspectAvatarUtil::registerFloater(); - LLInspectGroupUtil::registerFloater(); - LLInspectObjectUtil::registerFloater(); - LLInspectRemoteObjectUtil::registerFloater(); - LLFloaterVoiceVolumeUtil::registerFloater(); - LLNotificationsUI::registerFloater(); - LLFloaterDisplayNameUtil::registerFloater(); - - LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLInspectAvatarUtil::registerFloater(); + LLInspectGroupUtil::registerFloater(); + LLInspectObjectUtil::registerFloater(); + LLInspectRemoteObjectUtil::registerFloater(); + LLFloaterVoiceVolumeUtil::registerFloater(); + LLNotificationsUI::registerFloater(); + LLFloaterDisplayNameUtil::registerFloater(); + + LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build); LLFloaterReg::add("lua_scripts", "floater_lua_scripts.xml", (LLFloaterBuildFunc) &LLFloaterReg::build); - - LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("new_feature_notification", "floater_new_feature_notification.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterPayUtil::registerFloater(); - - LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); - LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterPayUtil::registerFloater(); + + LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("material_editor", "floater_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("live_material_editor", "floater_live_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build); - LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build); - //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build); - LLFloaterReg::add("test_textbox", "floater_test_textbox.xml", &LLFloaterReg::build); - LLFloaterReg::add("test_text_editor", "floater_test_text_editor.xml", &LLFloaterReg::build); - LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build); - LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("toybox", "floater_toybox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); - LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build); + LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build); + //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build); + LLFloaterReg::add("test_textbox", "floater_test_textbox.xml", &LLFloaterReg::build); + LLFloaterReg::add("test_text_editor", "floater_test_text_editor.xml", &LLFloaterReg::build); + LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build); + LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("toybox", "floater_toybox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); + LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("simple_snapshot", "floater_simple_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterUIPreviewUtil::registerFloater(); - LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); - - LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); - LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build); - LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - // *NOTE: Please keep these alphabetized for easier merges - - LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving + LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterUIPreviewUtil::registerFloater(); + LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + + LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); + LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("window_size", "floater_window_size.xml", &LLFloaterReg::build); + LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 52128a09ab..9f43fa1ac2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenu.cpp * @brief Builds menus out of items. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, 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$ */ @@ -30,7 +30,7 @@ #include "vld.h" #endif -#include "llviewermenu.h" +#include "llviewermenu.h" // linden library includes #include "llavatarnamecache.h" // IDEVO (I Are Not Men!) @@ -115,7 +115,7 @@ #include "llviewerdisplay.h" //for gWindowResized #include "llviewergenericmessage.h" #include "llviewerhelp.h" -#include "llviewermenufile.h" // init_menu_file() +#include "llviewermenufile.h" // init_menu_file() #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" @@ -159,7 +159,7 @@ void handle_test_load_url(void*); // // Evil hackish imported globals -//extern BOOL gHideSelectedObjects; +//extern BOOL gHideSelectedObjects; //extern BOOL gAllowSelectAvatar; //extern BOOL gDebugAvatarRotation; extern BOOL gDebugClicks; @@ -175,20 +175,20 @@ extern BOOL gShaderProfileFrame; LLUIListener sUIListener; -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuGL *gPopupMenuView = NULL; -LLMenuGL *gEditMenu = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; +LLMenuBarGL *gMenuBarView = NULL; +LLViewerMenuHolderGL *gMenuHolder = NULL; +LLMenuGL *gPopupMenuView = NULL; +LLMenuGL *gEditMenu = NULL; +LLMenuBarGL *gLoginMenuBarView = NULL; // Pie menus -LLContextMenu *gMenuAvatarSelf = NULL; -LLContextMenu *gMenuAvatarOther = NULL; -LLContextMenu *gMenuObject = NULL; -LLContextMenu *gMenuAttachmentSelf = NULL; -LLContextMenu *gMenuAttachmentOther = NULL; -LLContextMenu *gMenuLand = NULL; -LLContextMenu *gMenuMuteParticle = NULL; +LLContextMenu *gMenuAvatarSelf = NULL; +LLContextMenu *gMenuAvatarOther = NULL; +LLContextMenu *gMenuObject = NULL; +LLContextMenu *gMenuAttachmentSelf = NULL; +LLContextMenu *gMenuAttachmentOther = NULL; +LLContextMenu *gMenuLand = NULL; +LLContextMenu *gMenuMuteParticle = NULL; const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); @@ -286,7 +286,7 @@ void handle_force_parcel_owner_to_me(void*); void handle_force_parcel_to_content(void*); void handle_claim_public_land(void*); -void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry +void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry void reload_vertex_shader(void *); void handle_disconnect_viewer(void *); @@ -346,26 +346,26 @@ void menu_toggle_attached_particles(void* user_data); class LLMenuParcelObserver : public LLParcelObserver { public: - LLMenuParcelObserver(); - ~LLMenuParcelObserver(); - virtual void changed(); + LLMenuParcelObserver(); + ~LLMenuParcelObserver(); + virtual void changed(); }; static LLMenuParcelObserver* gMenuParcelObserver = NULL; LLMenuParcelObserver::LLMenuParcelObserver() { - LLViewerParcelMgr::getInstance()->addObserver(this); + LLViewerParcelMgr::getInstance()->addObserver(this); } LLMenuParcelObserver::~LLMenuParcelObserver() { - LLViewerParcelMgr::getInstance()->removeObserver(this); + LLViewerParcelMgr::getInstance()->removeObserver(this); } void LLMenuParcelObserver::changed() { - LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); if (gMenuLand && parcel) { LLView* child = gMenuLand->findChild("Land Buy Pass"); @@ -438,131 +438,131 @@ void check_merchant_status(bool force) void init_menus() { - // Initialize actions - initialize_menus(); - - /// - /// Popup menu - /// - /// The popup menu is now populated by the show_context_menu() - /// method. - - LLMenuGL::Params menu_params; - menu_params.name = "Popup"; - menu_params.visible = false; - gPopupMenuView = LLUICtrlFactory::create(menu_params); - gMenuHolder->addChild( gPopupMenuView ); - - /// - /// Context menus - /// - - const widget_registry_t& registry = - LLViewerMenuHolderGL::child_registry_t::instance(); - gEditMenu = LLUICtrlFactory::createFromFile("menu_edit.xml", gMenuHolder, registry); - gMenuAvatarSelf = LLUICtrlFactory::createFromFile( - "menu_avatar_self.xml", gMenuHolder, registry); - gMenuAvatarOther = LLUICtrlFactory::createFromFile( - "menu_avatar_other.xml", gMenuHolder, registry); - - gDetachScreenPieMenu = gMenuHolder->getChild("Object Detach HUD", true); - gDetachPieMenu = gMenuHolder->getChild("Object Detach", true); - - gMenuObject = LLUICtrlFactory::createFromFile( - "menu_object.xml", gMenuHolder, registry); - - gAttachScreenPieMenu = gMenuHolder->getChild("Object Attach HUD"); - gAttachPieMenu = gMenuHolder->getChild("Object Attach"); - - gMenuAttachmentSelf = LLUICtrlFactory::createFromFile( - "menu_attachment_self.xml", gMenuHolder, registry); - gMenuAttachmentOther = LLUICtrlFactory::createFromFile( - "menu_attachment_other.xml", gMenuHolder, registry); - - gDetachHUDAttSelfMenu = gMenuHolder->getChild("Detach Self HUD", true); - gDetachAttSelfMenu = gMenuHolder->getChild("Detach Self", true); - - gMenuLand = LLUICtrlFactory::createFromFile( - "menu_land.xml", gMenuHolder, registry); - - gMenuMuteParticle = LLUICtrlFactory::createFromFile( - "menu_mute_particle.xml", gMenuHolder, registry); - - /// - /// set up the colors - /// - LLColor4 color; - - LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); - - gMenuAvatarSelf->setBackgroundColor( context_menu_color ); - gMenuAvatarOther->setBackgroundColor( context_menu_color ); - gMenuObject->setBackgroundColor( context_menu_color ); - gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); - gMenuAttachmentOther->setBackgroundColor( context_menu_color ); - - gMenuLand->setBackgroundColor( context_menu_color ); - - color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); - gPopupMenuView->setBackgroundColor( color ); - - // If we are not in production, use a different color to make it apparent. - if (LLGridManager::getInstance()->isInProductionGrid()) - { - color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); - } - else - { - color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); - } - - LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); - - gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); - gMenuBarView->setBackgroundColor( color ); - - menu_bar_holder->addChild(gMenuBarView); - - gViewerWindow->setMenuBackgroundColor(false, + // Initialize actions + initialize_menus(); + + /// + /// Popup menu + /// + /// The popup menu is now populated by the show_context_menu() + /// method. + + LLMenuGL::Params menu_params; + menu_params.name = "Popup"; + menu_params.visible = false; + gPopupMenuView = LLUICtrlFactory::create(menu_params); + gMenuHolder->addChild( gPopupMenuView ); + + /// + /// Context menus + /// + + const widget_registry_t& registry = + LLViewerMenuHolderGL::child_registry_t::instance(); + gEditMenu = LLUICtrlFactory::createFromFile("menu_edit.xml", gMenuHolder, registry); + gMenuAvatarSelf = LLUICtrlFactory::createFromFile( + "menu_avatar_self.xml", gMenuHolder, registry); + gMenuAvatarOther = LLUICtrlFactory::createFromFile( + "menu_avatar_other.xml", gMenuHolder, registry); + + gDetachScreenPieMenu = gMenuHolder->getChild("Object Detach HUD", true); + gDetachPieMenu = gMenuHolder->getChild("Object Detach", true); + + gMenuObject = LLUICtrlFactory::createFromFile( + "menu_object.xml", gMenuHolder, registry); + + gAttachScreenPieMenu = gMenuHolder->getChild("Object Attach HUD"); + gAttachPieMenu = gMenuHolder->getChild("Object Attach"); + + gMenuAttachmentSelf = LLUICtrlFactory::createFromFile( + "menu_attachment_self.xml", gMenuHolder, registry); + gMenuAttachmentOther = LLUICtrlFactory::createFromFile( + "menu_attachment_other.xml", gMenuHolder, registry); + + gDetachHUDAttSelfMenu = gMenuHolder->getChild("Detach Self HUD", true); + gDetachAttSelfMenu = gMenuHolder->getChild("Detach Self", true); + + gMenuLand = LLUICtrlFactory::createFromFile( + "menu_land.xml", gMenuHolder, registry); + + gMenuMuteParticle = LLUICtrlFactory::createFromFile( + "menu_mute_particle.xml", gMenuHolder, registry); + + /// + /// set up the colors + /// + LLColor4 color; + + LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); + + gMenuAvatarSelf->setBackgroundColor( context_menu_color ); + gMenuAvatarOther->setBackgroundColor( context_menu_color ); + gMenuObject->setBackgroundColor( context_menu_color ); + gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); + gMenuAttachmentOther->setBackgroundColor( context_menu_color ); + + gMenuLand->setBackgroundColor( context_menu_color ); + + color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); + gPopupMenuView->setBackgroundColor( color ); + + // If we are not in production, use a different color to make it apparent. + if (LLGridManager::getInstance()->isInProductionGrid()) + { + color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); + } + else + { + color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); + } + + LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); + + gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT)); + gMenuBarView->setBackgroundColor( color ); + + menu_bar_holder->addChild(gMenuBarView); + + gViewerWindow->setMenuBackgroundColor(false, LLGridManager::getInstance()->isInProductionGrid()); - // *TODO:Also fix cost in llfolderview.cpp for Inventory menus - const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); - const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); - const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); - gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); - - gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); - gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); - - gDetachAvatarMenu = gMenuHolder->getChild("Avatar Detach", true); - gDetachHUDAvatarMenu = gMenuHolder->getChild("Avatar Detach HUD", true); - - // Don't display the Memory console menu if the feature is turned off - LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild("Memory", TRUE); - if (memoryMenu) - { - memoryMenu->setVisible(FALSE); - } - - gMenuBarView->createJumpKeys(); - - // Let land based option enable when parcel changes - gMenuParcelObserver = new LLMenuParcelObserver(); - - gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gLoginMenuBarView->arrangeAndClear(); - LLRect menuBarRect = gLoginMenuBarView->getRect(); - menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); - gLoginMenuBarView->setRect(menuBarRect); - gLoginMenuBarView->setBackgroundColor( color ); - menu_bar_holder->addChild(gLoginMenuBarView); - - // tooltips are on top of EVERYTHING, including menus - gViewerWindow->getRootView()->sendChildToFront(gToolTipView); + // *TODO:Also fix cost in llfolderview.cpp for Inventory menus + const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); + const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); + const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); + gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); + + gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); + gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); + + gDetachAvatarMenu = gMenuHolder->getChild("Avatar Detach", true); + gDetachHUDAvatarMenu = gMenuHolder->getChild("Avatar Detach HUD", true); + + // Don't display the Memory console menu if the feature is turned off + LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild("Memory", TRUE); + if (memoryMenu) + { + memoryMenu->setVisible(FALSE); + } + + gMenuBarView->createJumpKeys(); + + // Let land based option enable when parcel changes + gMenuParcelObserver = new LLMenuParcelObserver(); + + gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gLoginMenuBarView->arrangeAndClear(); + LLRect menuBarRect = gLoginMenuBarView->getRect(); + menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); + gLoginMenuBarView->setRect(menuBarRect); + gLoginMenuBarView->setBackgroundColor( color ); + menu_bar_holder->addChild(gLoginMenuBarView); + + // tooltips are on top of EVERYTHING, including menus + gViewerWindow->getRootView()->sendChildToFront(gToolTipView); } /////////////////// @@ -572,62 +572,62 @@ void init_menus() class LLAdvancedToggleConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - if ("texture" == console_type) - { - toggle_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - toggle_visibility( (void*)static_cast(gDebugView->mDebugConsolep)); - } - else if ("fast timers" == console_type) - { - LLFloaterReg::toggleInstance("block_timers"); - } - else if ("scene view" == console_type) - { - toggle_visibility( (void*)gSceneView); - } - else if ("scene monitor" == console_type) - { - toggle_visibility( (void*)gSceneMonitorView); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string console_type = userdata.asString(); + if ("texture" == console_type) + { + toggle_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + toggle_visibility( (void*)static_cast(gDebugView->mDebugConsolep)); + } + else if ("fast timers" == console_type) + { + LLFloaterReg::toggleInstance("block_timers"); + } + else if ("scene view" == console_type) + { + toggle_visibility( (void*)gSceneView); + } + else if ("scene monitor" == console_type) + { + toggle_visibility( (void*)gSceneMonitorView); + } + + return true; + } }; class LLAdvancedCheckConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - bool new_value = false; - if ("texture" == console_type) - { - new_value = get_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); - } - else if ("fast timers" == console_type) - { - new_value = LLFloaterReg::instanceVisible("block_timers"); - } - else if ("scene view" == console_type) - { - new_value = get_visibility( (void*) gSceneView); - } - else if ("scene monitor" == console_type) - { - new_value = get_visibility( (void*) gSceneMonitorView); - } - - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string console_type = userdata.asString(); + bool new_value = false; + if ("texture" == console_type) + { + new_value = get_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); + } + else if ("fast timers" == console_type) + { + new_value = LLFloaterReg::instanceVisible("block_timers"); + } + else if ("scene view" == console_type) + { + new_value = get_visibility( (void*) gSceneView); + } + else if ("scene monitor" == console_type) + { + new_value = get_visibility( (void*) gSceneMonitorView); + } + + return new_value; + } }; @@ -638,24 +638,24 @@ class LLAdvancedCheckConsole : public view_listener_t class LLAdvancedDumpInfoToConsole : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugView->mDebugConsolep->setVisible(TRUE); - std::string info_type = userdata.asString(); - if ("region" == info_type) - { - handle_region_dump_settings(NULL); - } - else if ("group" == info_type) - { - handle_dump_group_info(NULL); - } - else if ("capabilities" == info_type) - { - handle_dump_capabilities_info(NULL); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugView->mDebugConsolep->setVisible(TRUE); + std::string info_type = userdata.asString(); + if ("region" == info_type) + { + handle_region_dump_settings(NULL); + } + else if ("group" == info_type) + { + handle_dump_group_info(NULL); + } + else if ("capabilities" == info_type) + { + handle_dump_capabilities_info(NULL); + } + return true; + } }; @@ -666,54 +666,54 @@ class LLAdvancedDumpInfoToConsole : public view_listener_t class LLAdvancedToggleHUDInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - - if ("camera" == info_type) - { - gDisplayCameraPos = !(gDisplayCameraPos); - } - else if ("wind" == info_type) - { - gDisplayWindInfo = !(gDisplayWindInfo); - } - else if ("fov" == info_type) - { - gDisplayFOV = !(gDisplayFOV); - } - else if ("badge" == info_type) - { - gDisplayBadge = !(gDisplayBadge); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + + if ("camera" == info_type) + { + gDisplayCameraPos = !(gDisplayCameraPos); + } + else if ("wind" == info_type) + { + gDisplayWindInfo = !(gDisplayWindInfo); + } + else if ("fov" == info_type) + { + gDisplayFOV = !(gDisplayFOV); + } + else if ("badge" == info_type) + { + gDisplayBadge = !(gDisplayBadge); + } + return true; + } }; class LLAdvancedCheckHUDInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - bool new_value = false; - if ("camera" == info_type) - { - new_value = gDisplayCameraPos; - } - else if ("wind" == info_type) - { - new_value = gDisplayWindInfo; - } - else if ("fov" == info_type) - { - new_value = gDisplayFOV; - } - else if ("badge" == info_type) - { - new_value = gDisplayBadge; - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + bool new_value = false; + if ("camera" == info_type) + { + new_value = gDisplayCameraPos; + } + else if ("wind" == info_type) + { + new_value = gDisplayWindInfo; + } + else if ("fov" == info_type) + { + new_value = gDisplayFOV; + } + else if ("badge" == info_type) + { + new_value = gDisplayBadge; + } + return new_value; + } }; @@ -723,11 +723,11 @@ class LLAdvancedCheckHUDInfo : public view_listener_t class LLAdvancedClearGroupCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLGroupMgr::debugClearAllGroups(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLGroupMgr::debugClearAllGroups(NULL); + return true; + } }; @@ -738,97 +738,97 @@ class LLAdvancedClearGroupCache : public view_listener_t ///////////////// U32 render_type_from_string(std::string render_type) { - if ("simple" == render_type) - { - return LLPipeline::RENDER_TYPE_SIMPLE; - } - else if ("alpha" == render_type) - { - return LLPipeline::RENDER_TYPE_ALPHA; - } - else if ("tree" == render_type) - { - return LLPipeline::RENDER_TYPE_TREE; - } - else if ("character" == render_type) - { - return LLPipeline::RENDER_TYPE_AVATAR; - } - else if ("controlAV" == render_type) // Animesh - { - return LLPipeline::RENDER_TYPE_CONTROL_AV; - } - else if ("surfacePatch" == render_type) - { - return LLPipeline::RENDER_TYPE_TERRAIN; - } - else if ("sky" == render_type) - { - return LLPipeline::RENDER_TYPE_SKY; - } - else if ("water" == render_type) - { - return LLPipeline::RENDER_TYPE_WATER; - } - else if ("volume" == render_type) - { - return LLPipeline::RENDER_TYPE_VOLUME; - } - else if ("grass" == render_type) - { - return LLPipeline::RENDER_TYPE_GRASS; - } - else if ("clouds" == render_type) - { - return LLPipeline::RENDER_TYPE_CLOUDS; - } - else if ("particles" == render_type) - { - return LLPipeline::RENDER_TYPE_PARTICLES; - } - else if ("bump" == render_type) - { - return LLPipeline::RENDER_TYPE_BUMP; - } - else if ("pbr" == render_type) + if ("simple" == render_type) + { + return LLPipeline::RENDER_TYPE_SIMPLE; + } + else if ("alpha" == render_type) + { + return LLPipeline::RENDER_TYPE_ALPHA; + } + else if ("tree" == render_type) + { + return LLPipeline::RENDER_TYPE_TREE; + } + else if ("character" == render_type) + { + return LLPipeline::RENDER_TYPE_AVATAR; + } + else if ("controlAV" == render_type) // Animesh + { + return LLPipeline::RENDER_TYPE_CONTROL_AV; + } + else if ("surfacePatch" == render_type) + { + return LLPipeline::RENDER_TYPE_TERRAIN; + } + else if ("sky" == render_type) + { + return LLPipeline::RENDER_TYPE_SKY; + } + else if ("water" == render_type) + { + return LLPipeline::RENDER_TYPE_WATER; + } + else if ("volume" == render_type) + { + return LLPipeline::RENDER_TYPE_VOLUME; + } + else if ("grass" == render_type) + { + return LLPipeline::RENDER_TYPE_GRASS; + } + else if ("clouds" == render_type) + { + return LLPipeline::RENDER_TYPE_CLOUDS; + } + else if ("particles" == render_type) + { + return LLPipeline::RENDER_TYPE_PARTICLES; + } + else if ("bump" == render_type) + { + return LLPipeline::RENDER_TYPE_BUMP; + } + else if ("pbr" == render_type) { return LLPipeline::RENDER_TYPE_GLTF_PBR; } - else - { - return 0; - } + else + { + return 0; + } } class LLAdvancedToggleRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - if ( render_type != 0 ) - { - LLPipeline::toggleRenderTypeControl( render_type ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + if ( render_type != 0 ) + { + LLPipeline::toggleRenderTypeControl( render_type ); + } + return true; + } }; class LLAdvancedCheckRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - bool new_value = false; + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + bool new_value = false; - if ( render_type != 0 ) - { - new_value = LLPipeline::hasRenderTypeControl( render_type ); - } + if ( render_type != 0 ) + { + new_value = LLPipeline::hasRenderTypeControl( render_type ); + } - return new_value; - } + return new_value; + } }; @@ -836,140 +836,140 @@ class LLAdvancedCheckRenderType : public view_listener_t // FEATURE // ///////////// U32 feature_from_string(std::string feature) -{ - if ("ui" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_UI; - } - else if ("selected" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; - } - else if ("highlighted" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; - } - else if ("dynamic textures" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; - } - else if ("foot shadows" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; - } - else if ("fog" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOG; - } - else if ("fr info" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; - } - else if ("flexible" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; - } - else - { - return 0; - } +{ + if ("ui" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_UI; + } + else if ("selected" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; + } + else if ("highlighted" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; + } + else if ("dynamic textures" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; + } + else if ("foot shadows" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; + } + else if ("fog" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOG; + } + else if ("fr info" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; + } + else if ("flexible" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; + } + else + { + return 0; + } }; class LLAdvancedToggleFeature : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 feature = feature_from_string( userdata.asString() ); - if ( feature != 0 ) - { - LLPipeline::toggleRenderDebugFeature( feature ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 feature = feature_from_string( userdata.asString() ); + if ( feature != 0 ) + { + LLPipeline::toggleRenderDebugFeature( feature ); + } + return true; + } }; class LLAdvancedCheckFeature : public view_listener_t { - bool handleEvent(const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - U32 feature = feature_from_string( userdata.asString() ); - bool new_value = false; + U32 feature = feature_from_string( userdata.asString() ); + bool new_value = false; - if ( feature != 0 ) - { - new_value = LLPipeline::toggleRenderDebugFeatureControl( feature ); - } + if ( feature != 0 ) + { + new_value = LLPipeline::toggleRenderDebugFeatureControl( feature ); + } - return new_value; + return new_value; } }; class LLAdvancedCheckDisplayTextureDensity : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string mode = userdata.asString(); - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) - { - return mode == "none"; - } - if (mode == "current") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_CURRENT; - } - else if (mode == "desired") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_DESIRED; - } - else if (mode == "full") - { - return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_FULL; - } - return false; - } + bool handleEvent(const LLSD& userdata) + { + std::string mode = userdata.asString(); + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) + { + return mode == "none"; + } + if (mode == "current") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_CURRENT; + } + else if (mode == "desired") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_DESIRED; + } + else if (mode == "full") + { + return LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_FULL; + } + return false; + } }; class LLAdvancedSetDisplayTextureDensity : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string mode = userdata.asString(); - if (mode == "none") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == TRUE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; - } - else if (mode == "current") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_CURRENT; - } - else if (mode == "desired") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY, true); - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_DESIRED; - } - else if (mode == "full") - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) - { - gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); - } - LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_FULL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string mode = userdata.asString(); + if (mode == "none") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == TRUE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; + } + else if (mode == "current") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_CURRENT; + } + else if (mode == "desired") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY, true); + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_DESIRED; + } + else if (mode == "full") + { + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY) == FALSE) + { + gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY); + } + LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_FULL; + } + return true; + } }; @@ -978,232 +978,232 @@ class LLAdvancedSetDisplayTextureDensity : public view_listener_t ////////////////// U64 info_display_from_string(std::string info_display) { - if ("verify" == info_display) - { - return LLPipeline::RENDER_DEBUG_VERIFY; - } - else if ("bboxes" == info_display) - { - return LLPipeline::RENDER_DEBUG_BBOXES; - } - else if ("normals" == info_display) - { - return LLPipeline::RENDER_DEBUG_NORMALS; - } - else if ("points" == info_display) - { - return LLPipeline::RENDER_DEBUG_POINTS; - } - else if ("octree" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCTREE; - } - else if ("shadow frusta" == info_display) - { - return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; - } - else if ("physics shapes" == info_display) - { - return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; - } - else if ("occlusion" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCCLUSION; - } - else if ("render batches" == info_display) - { - return LLPipeline::RENDER_DEBUG_BATCH_SIZE; - } - else if ("update type" == info_display) - { - return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; - } - else if ("texture anim" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; - } - else if ("texture priority" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; - } - else if ("texture area" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; - } - else if ("face area" == info_display) - { - return LLPipeline::RENDER_DEBUG_FACE_AREA; - } - else if ("lod info" == info_display) - { - return LLPipeline::RENDER_DEBUG_LOD_INFO; - } - else if ("lights" == info_display) - { - return LLPipeline::RENDER_DEBUG_LIGHTS; - } - else if ("particles" == info_display) - { - return LLPipeline::RENDER_DEBUG_PARTICLES; - } - else if ("composition" == info_display) - { - return LLPipeline::RENDER_DEBUG_COMPOSITION; - } - else if ("avatardrawinfo" == info_display) - { - return (LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO); - } - else if ("glow" == info_display) - { - return LLPipeline::RENDER_DEBUG_GLOW; - } - else if ("collision skeleton" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; - } - else if ("joints" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS; - } - else if ("raycast" == info_display) - { - return LLPipeline::RENDER_DEBUG_RAYCAST; - } - else if ("agent target" == info_display) - { - return LLPipeline::RENDER_DEBUG_AGENT_TARGET; - } - else if ("sculpt" == info_display) - { - return LLPipeline::RENDER_DEBUG_SCULPTED; - } - else if ("wind vectors" == info_display) - { - return LLPipeline::RENDER_DEBUG_WIND_VECTORS; - } - else if ("texel density" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY; - } - else if ("triangle count" == info_display) - { - return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; - } - else if ("impostors" == info_display) - { - return LLPipeline::RENDER_DEBUG_IMPOSTORS; - } - else if ("reflection probes" == info_display) + if ("verify" == info_display) { - return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + return LLPipeline::RENDER_DEBUG_VERIFY; } - else if ("probe updates" == info_display) + else if ("bboxes" == info_display) { - return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; + return LLPipeline::RENDER_DEBUG_BBOXES; } - else - { - LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; - return 0; - } -}; - -class LLAdvancedToggleInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U64 info_display = info_display_from_string( userdata.asString() ); - - LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; - - if ( info_display != 0 ) - { - LLPipeline::toggleRenderDebug( info_display ); - } - - return true; - } -}; - - -class LLAdvancedCheckInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U64 info_display = info_display_from_string( userdata.asString() ); - bool new_value = false; - - if ( info_display != 0 ) - { - new_value = LLPipeline::toggleRenderDebugControl( info_display ); - } - - return new_value; - } -}; - - -/////////////////////////// -//// RANDOMIZE FRAMERATE // -/////////////////////////// - - -class LLAdvancedToggleRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gRandomizeFramerate = !(gRandomizeFramerate); - return true; - } -}; - -class LLAdvancedCheckRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gRandomizeFramerate; - return new_value; - } -}; - -/////////////////////////// -//// PERIODIC SLOW FRAME // -/////////////////////////// - - -class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gPeriodicSlowFrame = !(gPeriodicSlowFrame); - return true; - } -}; - -class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gPeriodicSlowFrame; - return new_value; - } -}; - - -/////////////////////////// -// SELECTED TEXTURE INFO // -// + else if ("normals" == info_display) + { + return LLPipeline::RENDER_DEBUG_NORMALS; + } + else if ("points" == info_display) + { + return LLPipeline::RENDER_DEBUG_POINTS; + } + else if ("octree" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCTREE; + } + else if ("shadow frusta" == info_display) + { + return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; + } + else if ("physics shapes" == info_display) + { + return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; + } + else if ("occlusion" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCCLUSION; + } + else if ("render batches" == info_display) + { + return LLPipeline::RENDER_DEBUG_BATCH_SIZE; + } + else if ("update type" == info_display) + { + return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; + } + else if ("texture anim" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; + } + else if ("texture priority" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; + } + else if ("texture area" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; + } + else if ("face area" == info_display) + { + return LLPipeline::RENDER_DEBUG_FACE_AREA; + } + else if ("lod info" == info_display) + { + return LLPipeline::RENDER_DEBUG_LOD_INFO; + } + else if ("lights" == info_display) + { + return LLPipeline::RENDER_DEBUG_LIGHTS; + } + else if ("particles" == info_display) + { + return LLPipeline::RENDER_DEBUG_PARTICLES; + } + else if ("composition" == info_display) + { + return LLPipeline::RENDER_DEBUG_COMPOSITION; + } + else if ("avatardrawinfo" == info_display) + { + return (LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO); + } + else if ("glow" == info_display) + { + return LLPipeline::RENDER_DEBUG_GLOW; + } + else if ("collision skeleton" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; + } + else if ("joints" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS; + } + else if ("raycast" == info_display) + { + return LLPipeline::RENDER_DEBUG_RAYCAST; + } + else if ("agent target" == info_display) + { + return LLPipeline::RENDER_DEBUG_AGENT_TARGET; + } + else if ("sculpt" == info_display) + { + return LLPipeline::RENDER_DEBUG_SCULPTED; + } + else if ("wind vectors" == info_display) + { + return LLPipeline::RENDER_DEBUG_WIND_VECTORS; + } + else if ("texel density" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY; + } + else if ("triangle count" == info_display) + { + return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; + } + else if ("impostors" == info_display) + { + return LLPipeline::RENDER_DEBUG_IMPOSTORS; + } + else if ("reflection probes" == info_display) + { + return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + } + else if ("probe updates" == info_display) + { + return LLPipeline::RENDER_DEBUG_PROBE_UPDATES; + } + else + { + LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; + return 0; + } +}; + +class LLAdvancedToggleInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); + + LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL; + + if ( info_display != 0 ) + { + LLPipeline::toggleRenderDebug( info_display ); + } + + return true; + } +}; + + +class LLAdvancedCheckInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U64 info_display = info_display_from_string( userdata.asString() ); + bool new_value = false; + + if ( info_display != 0 ) + { + new_value = LLPipeline::toggleRenderDebugControl( info_display ); + } + + return new_value; + } +}; + + +/////////////////////////// +//// RANDOMIZE FRAMERATE // +/////////////////////////// + + +class LLAdvancedToggleRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gRandomizeFramerate = !(gRandomizeFramerate); + return true; + } +}; + +class LLAdvancedCheckRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gRandomizeFramerate; + return new_value; + } +}; + +/////////////////////////// +//// PERIODIC SLOW FRAME // +/////////////////////////// + + +class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gPeriodicSlowFrame = !(gPeriodicSlowFrame); + return true; + } +}; + +class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gPeriodicSlowFrame; + return new_value; + } +}; + + +/////////////////////////// +// SELECTED TEXTURE INFO // +// /////////////////////////// class LLAdvancedSelectedTextureInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_selected_texture_info(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_selected_texture_info(NULL); + return true; + } }; ////////////////////// @@ -1212,33 +1212,33 @@ class LLAdvancedSelectedTextureInfo : public view_listener_t class LLAdvancedToggleWireframe : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gUseWireframe = !(gUseWireframe); + bool handleEvent(const LLSD& userdata) + { + gUseWireframe = !(gUseWireframe); - return true; - } + return true; + } }; class LLAdvancedCheckWireframe : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gUseWireframe; - } + bool handleEvent(const LLSD& userdata) + { + return gUseWireframe; + } }; - + ////////////////////////// // DUMP SCRIPTED CAMERA // ////////////////////////// - + class LLAdvancedDumpScriptedCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_followcam(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_dump_followcam(NULL); + return true; } }; @@ -1251,11 +1251,11 @@ class LLAdvancedDumpScriptedCamera : public view_listener_t class LLAdvancedDumpRegionObjectCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_region_object_cache(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_dump_region_object_cache(NULL); + return true; + } }; class LLAdvancedToggleInterestList360Mode : public view_listener_t @@ -1266,22 +1266,22 @@ public: // Toggle the mode - regions will get updated if (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360) { - gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); - } - else - { - gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); - } + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); + } + else + { + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); + } return true; } }; class LLAdvancedCheckInterestList360Mode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); + } }; class LLAdvancedToggleStatsRecorder : public view_listener_t @@ -1289,13 +1289,13 @@ class LLAdvancedToggleStatsRecorder : public view_listener_t bool handleEvent(const LLSD &userdata) { if (LLViewerStatsRecorder::instance().isEnabled()) - { // Turn off both recording and logging - LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); - } - else - { // Turn on both recording and logging - LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); - } + { // Turn off both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); + } + else + { // Turn on both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); + } return true; } }; @@ -1303,7 +1303,7 @@ class LLAdvancedToggleStatsRecorder : public view_listener_t class LLAdvancedCheckStatsRecorder : public view_listener_t { bool handleEvent(const LLSD &userdata) - { // Use the logging state as the indicator of whether the stats recorder is on + { // Use the logging state as the indicator of whether the stats recorder is on return LLViewerStatsRecorder::instance().isLogging(); } }; @@ -1311,7 +1311,7 @@ class LLAdvancedCheckStatsRecorder : public view_listener_t class LLAdvancedResetInterestLists : public view_listener_t { bool handleEvent(const LLSD &userdata) - { // Reset all region interest lists + { // Reset all region interest lists handle_reset_interest_lists(NULL); return true; } @@ -1319,12 +1319,12 @@ class LLAdvancedResetInterestLists : public view_listener_t class LLAdvancedBuyCurrencyTest : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - handle_buy_currency_test(NULL); - return true; - } + { + bool handleEvent(const LLSD& userdata) + { + handle_buy_currency_test(NULL); + return true; + } }; @@ -1335,11 +1335,11 @@ class LLAdvancedBuyCurrencyTest : public view_listener_t class LLAdvancedDumpSelectMgr : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - dump_select_mgr(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + dump_select_mgr(NULL); + return true; + } }; @@ -1351,11 +1351,11 @@ class LLAdvancedDumpSelectMgr : public view_listener_t class LLAdvancedDumpInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - dump_inventory(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + dump_inventory(NULL); + return true; + } }; @@ -1367,11 +1367,11 @@ class LLAdvancedDumpInventory : public view_listener_t class LLAdvancedPrintSelectedObjectInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - print_object_info(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + print_object_info(NULL); + return true; + } }; @@ -1383,11 +1383,11 @@ class LLAdvancedPrintSelectedObjectInfo : public view_listener_t class LLAdvancedPrintAgentInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - print_agent_nvpairs(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + print_agent_nvpairs(NULL); + return true; + } }; ////////////////// @@ -1397,20 +1397,20 @@ class LLAdvancedPrintAgentInfo : public view_listener_t class LLAdvancedToggleDebugClicks : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugClicks = !(gDebugClicks); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugClicks = !(gDebugClicks); + return true; + } }; class LLAdvancedCheckDebugClicks : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugClicks; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugClicks; + return new_value; + } }; @@ -1422,20 +1422,20 @@ class LLAdvancedCheckDebugClicks : public view_listener_t class LLAdvancedToggleDebugViews : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugRects = !(LLView::sDebugRects); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugRects = !(LLView::sDebugRects); + return true; + } }; class LLAdvancedCheckDebugViews : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugRects; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugRects; + return new_value; + } }; @@ -1447,19 +1447,19 @@ class LLAdvancedCheckDebugViews : public view_listener_t class LLAdvancedToggleDebugUnicode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugUnicode = !(LLView::sDebugUnicode); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugUnicode = !(LLView::sDebugUnicode); + return true; + } }; class LLAdvancedCheckDebugUnicode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return LLView::sDebugUnicode; - } + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugUnicode; + } }; @@ -1471,20 +1471,20 @@ class LLAdvancedCheckDebugUnicode : public view_listener_t class LLAdvancedToggleDebugCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugCamera = !(LLView::sDebugCamera); - LLFloaterCamera::onDebugCameraToggled(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugCamera = !(LLView::sDebugCamera); + LLFloaterCamera::onDebugCameraToggled(); + return true; + } }; class LLAdvancedCheckDebugCamera : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return LLView::sDebugCamera; - } + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugCamera; + } }; @@ -1496,20 +1496,20 @@ class LLAdvancedCheckDebugCamera : public view_listener_t class LLAdvancedToggleXUINameTooltips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } }; class LLAdvancedCheckXUINameTooltips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } }; @@ -1521,20 +1521,20 @@ class LLAdvancedCheckXUINameTooltips : public view_listener_t class LLAdvancedToggleDebugMouseEvents : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); + return true; + } }; class LLAdvancedCheckDebugMouseEvents : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugMouseHandling; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugMouseHandling; + return new_value; + } }; @@ -1546,22 +1546,22 @@ class LLAdvancedCheckDebugMouseEvents : public view_listener_t class LLAdvancedToggleDebugKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugKeys = !(LLView::sDebugKeys); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugKeys = !(LLView::sDebugKeys); + return true; + } }; - + class LLAdvancedCheckDebugKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugKeys; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugKeys; + return new_value; + } }; - + /////////////////////// @@ -1571,30 +1571,30 @@ class LLAdvancedCheckDebugKeys : public view_listener_t class LLAdvancedToggleDebugWindowProc : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gDebugWindowProc = !(gDebugWindowProc); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gDebugWindowProc = !(gDebugWindowProc); + return true; + } }; class LLAdvancedCheckDebugWindowProc : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugWindowProc; - return new_value; - } + { + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugWindowProc; + return new_value; + } }; // ------------------------------XUI MENU --------------------------- class LLAdvancedSendTestIms : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLIMModel::instance().testMessages(); - return true; + bool handleEvent(const LLSD& userdata) + { + LLIMModel::instance().testMessages(); + return true; } }; @@ -1606,22 +1606,22 @@ class LLAdvancedSendTestIms : public view_listener_t class LLAdvancedToggleXUINames : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } }; class LLAdvancedCheckXUINames : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } -}; - + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } +}; + //////////////////////// // GRAB BAKED TEXTURE // @@ -1630,71 +1630,71 @@ class LLAdvancedCheckXUINames : public view_listener_t class LLAdvancedGrabBakedTexture : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string texture_type = userdata.asString(); - if ("iris" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string texture_type = userdata.asString(); + if ("iris" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_EYES ); + } + else if ("head" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_HEAD ); + } + else if ("upper" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_UPPER ); + } + else if ("lower" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_LOWER ); + } + else if ("skirt" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_SKIRT ); + } + else if ("hair" == texture_type) + { + handle_grab_baked_texture( (void*)BAKED_HAIR ); + } + + return true; + } }; class LLAdvancedEnableGrabBakedTexture : public view_listener_t { - bool handleEvent(const LLSD& userdata) -{ - std::string texture_type = userdata.asString(); - bool new_value = false; - - if ("iris" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return new_value; + bool handleEvent(const LLSD& userdata) +{ + std::string texture_type = userdata.asString(); + bool new_value = false; + + if ("iris" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); + } + else if ("head" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); + } + else if ("upper" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); + } + else if ("lower" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); + } + else if ("skirt" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); + } + else if ("hair" == texture_type) + { + new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); + } + + return new_value; } }; @@ -1705,8 +1705,8 @@ class LLAdvancedEnableGrabBakedTexture : public view_listener_t class LLAdvancedEnableAppearanceToXML : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (obj && obj->isAnimatedObject() && obj->getControlAvatar()) { @@ -1721,18 +1721,18 @@ class LLAdvancedEnableAppearanceToXML : public view_listener_t // This has to be a non-control avatar, because control avs are invisible and unclickable. return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); } - else - { - return false; - } - } + else + { + return false; + } + } }; class LLAdvancedAppearanceToXML : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string emptyname; + bool handleEvent(const LLSD& userdata) + { + std::string emptyname; LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar *avatar = NULL; if (obj) @@ -1755,14 +1755,14 @@ class LLAdvancedAppearanceToXML : public view_listener_t else { // If no selection, use the self avatar. - avatar = gAgentAvatarp; + avatar = gAgentAvatarp; } if (avatar) { avatar->dumpArchetypeXML(emptyname); } - return true; - } + return true; + } }; @@ -1774,44 +1774,44 @@ class LLAdvancedAppearanceToXML : public view_listener_t class LLAdvancedToggleCharacterGeometry : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_god_request_avatar_geometry(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_god_request_avatar_geometry(NULL); + return true; } }; - ///////////////////////////// + ///////////////////////////// // TEST MALE / TEST FEMALE // ///////////////////////////// class LLAdvancedTestMale : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_test_male(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_test_male(NULL); + return true; + } }; class LLAdvancedTestFemale : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_test_female(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_test_female(NULL); + return true; + } }; class LLAdvancedForceParamsToDefault : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAgent::clearVisualParams(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAgent::clearVisualParams(NULL); + return true; + } }; @@ -1820,47 +1820,47 @@ class LLAdvancedForceParamsToDefault : public view_listener_t ////////////////////////// // Utility function to set all AV time factors to the same global value -static void set_all_animation_time_factors(F32 time_factor) +static void set_all_animation_time_factors(F32 time_factor) { - LLMotionController::setCurrentTimeFactor(time_factor); - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - (*iter)->setAnimTimeFactor(time_factor); - } + LLMotionController::setCurrentTimeFactor(time_factor); + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + (*iter)->setAnimTimeFactor(time_factor); + } } class LLAdvancedAnimTenFaster : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //LL_INFOS() << "LLAdvancedAnimTenFaster" << LL_ENDL; - F32 time_factor = LLMotionController::getCurrentTimeFactor(); - time_factor = llmin(time_factor + 0.1f, 2.f); // Upper limit is 200% speed - set_all_animation_time_factors(time_factor); - return true; - } + bool handleEvent(const LLSD& userdata) + { + //LL_INFOS() << "LLAdvancedAnimTenFaster" << LL_ENDL; + F32 time_factor = LLMotionController::getCurrentTimeFactor(); + time_factor = llmin(time_factor + 0.1f, 2.f); // Upper limit is 200% speed + set_all_animation_time_factors(time_factor); + return true; + } }; class LLAdvancedAnimTenSlower : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //LL_INFOS() << "LLAdvancedAnimTenSlower" << LL_ENDL; - F32 time_factor = LLMotionController::getCurrentTimeFactor(); - time_factor = llmax(time_factor - 0.1f, 0.1f); // Lower limit is at 10% of normal speed - set_all_animation_time_factors(time_factor); - return true; - } + bool handleEvent(const LLSD& userdata) + { + //LL_INFOS() << "LLAdvancedAnimTenSlower" << LL_ENDL; + F32 time_factor = LLMotionController::getCurrentTimeFactor(); + time_factor = llmax(time_factor - 0.1f, 0.1f); // Lower limit is at 10% of normal speed + set_all_animation_time_factors(time_factor); + return true; + } }; class LLAdvancedAnimResetAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - set_all_animation_time_factors(1.f); - return true; - } + bool handleEvent(const LLSD& userdata) + { + set_all_animation_time_factors(1.f); + return true; + } }; @@ -1871,11 +1871,11 @@ class LLAdvancedAnimResetAll : public view_listener_t class LLAdvancedReloadVertexShader : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - reload_vertex_shader(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + reload_vertex_shader(NULL); + return true; + } }; @@ -1887,20 +1887,20 @@ class LLAdvancedReloadVertexShader : public view_listener_t class LLAdvancedToggleAnimationInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); + return true; + } }; class LLAdvancedCheckAnimationInfo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sShowAnimationDebug; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sShowAnimationDebug; + return new_value; + } }; @@ -1911,20 +1911,20 @@ class LLAdvancedCheckAnimationInfo : public view_listener_t class LLAdvancedToggleShowLookAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); + return true; + } }; class LLAdvancedCheckShowLookAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectLookAt::sDebugLookAt; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectLookAt::sDebugLookAt; + return new_value; + } }; @@ -1936,20 +1936,20 @@ class LLAdvancedCheckShowLookAt : public view_listener_t class LLAdvancedToggleShowPointAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); + return true; + } }; class LLAdvancedCheckShowPointAt : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectPointAt::sDebugPointAt; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectPointAt::sDebugPointAt; + return new_value; + } }; @@ -1961,20 +1961,20 @@ class LLAdvancedCheckShowPointAt : public view_listener_t class LLAdvancedToggleDebugJointUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); + return true; + } }; class LLAdvancedCheckDebugJointUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sJointDebug; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sJointDebug; + return new_value; + } }; @@ -1986,20 +1986,20 @@ class LLAdvancedCheckDebugJointUpdates : public view_listener_t class LLAdvancedToggleDisableLOD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); + return true; + } }; - + class LLAdvancedCheckDisableLOD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoint::sDisableLOD; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoint::sDisableLOD; + return new_value; + } }; @@ -2011,20 +2011,20 @@ class LLAdvancedCheckDisableLOD : public view_listener_t class LLAdvancedToggleDebugCharacterVis : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); + return true; + } }; class LLAdvancedCheckDebugCharacterVis : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sDebugInvisible; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sDebugInvisible; + return new_value; + } }; @@ -2032,33 +2032,33 @@ class LLAdvancedCheckDebugCharacterVis : public view_listener_t // DUMP ATTACHMENTS // ////////////////////// - + class LLAdvancedDumpAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_dump_attachments(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_dump_attachments(NULL); + return true; + } }; - + ///////////////////// // REBAKE TEXTURES // ///////////////////// - - + + class LLAdvancedRebakeTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_rebake_textures(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_rebake_textures(NULL); + return true; + } }; - - + + #if 1 //ndef LL_RELEASE_FOR_DOWNLOAD /////////////////////////// // DEBUG AVATAR TEXTURES // @@ -2067,14 +2067,14 @@ class LLAdvancedRebakeTextures : public view_listener_t class LLAdvancedDebugAvatarTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isGodlike()) - { - handle_debug_avatar_textures(NULL); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.isGodlike()) + { + handle_debug_avatar_textures(NULL); + } + return true; + } }; //////////////////////////////// @@ -2084,17 +2084,17 @@ class LLAdvancedDebugAvatarTextures : public view_listener_t class LLAdvancedDumpAvatarLocalTextures : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { #ifndef LL_RELEASE_FOR_DOWNLOAD - handle_dump_avatar_local_textures(NULL); + handle_dump_avatar_local_textures(NULL); #endif - return true; - } + return true; + } }; #endif - + ///////////////// // MESSAGE LOG // ///////////////// @@ -2102,20 +2102,20 @@ class LLAdvancedDumpAvatarLocalTextures : public view_listener_t class LLAdvancedEnableMessageLog : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_viewer_enable_message_log(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_viewer_enable_message_log(NULL); + return true; + } }; class LLAdvancedDisableMessageLog : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_viewer_disable_message_log(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_viewer_disable_message_log(NULL); + return true; + } }; ///////////////// @@ -2125,11 +2125,11 @@ class LLAdvancedDisableMessageLog : public view_listener_t class LLAdvancedDropPacket : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gMessageSystem->mPacketRing.dropPackets(1); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gMessageSystem->mPacketRing.dropPackets(1); + return true; + } }; ////////////////////// @@ -2139,8 +2139,8 @@ class LLAdvancedDropPacket : public view_listener_t class LLAdvancedPurgeDiskCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General"); llassert_always(main_queue); @@ -2154,8 +2154,8 @@ class LLAdvancedPurgeDiskCache : public view_listener_t }, [](){}); // Callback to main thread is empty as there is nothing left to do - return true; - } + return true; + } }; @@ -2166,12 +2166,12 @@ class LLAdvancedPurgeDiskCache : public view_listener_t class LLAdvancedPurgeShaderCache : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerShaderMgr::instance()->clearShaderCache(); - LLViewerShaderMgr::instance()->setShaders(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerShaderMgr::instance()->clearShaderCache(); + LLViewerShaderMgr::instance()->setShaders(); + return true; + } }; //////////////////// @@ -2181,32 +2181,32 @@ class LLAdvancedPurgeShaderCache : public view_listener_t class LLAdvancedViewerEventRecorder : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - LL_INFOS() << "Event Playback starting" << LL_ENDL; - LLViewerEventRecorder::instance().playbackRecording(); - LL_INFOS() << "Event Playback completed" << LL_ENDL; - } - else if ("stop playback" == command) - { - // Future - } - else if ("start recording" == command) - { - LLViewerEventRecorder::instance().setEventLoggingOn(); - LL_INFOS() << "Event recording started" << LL_ENDL; - } - else if ("stop recording" == command) - { - LLViewerEventRecorder::instance().setEventLoggingOff(); - LL_INFOS() << "Event recording stopped" << LL_ENDL; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + LL_INFOS() << "Event Playback starting" << LL_ENDL; + LLViewerEventRecorder::instance().playbackRecording(); + LL_INFOS() << "Event Playback completed" << LL_ENDL; + } + else if ("stop playback" == command) + { + // Future + } + else if ("start recording" == command) + { + LLViewerEventRecorder::instance().setEventLoggingOn(); + LL_INFOS() << "Event recording started" << LL_ENDL; + } + else if ("stop recording" == command) + { + LLViewerEventRecorder::instance().setEventLoggingOff(); + LL_INFOS() << "Event recording stopped" << LL_ENDL; + } + + return true; + } }; @@ -2219,29 +2219,29 @@ class LLAdvancedViewerEventRecorder : public view_listener_t class LLAdvancedAgentPilot : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - gAgentPilot.setNumRuns(-1); - gAgentPilot.startPlayback(); - } - else if ("stop playback" == command) - { - gAgentPilot.stopPlayback(); - } - else if ("start record" == command) - { - gAgentPilot.startRecord(); - } - else if ("stop record" == command) - { - gAgentPilot.stopRecord(); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + gAgentPilot.setNumRuns(-1); + gAgentPilot.startPlayback(); + } + else if ("stop playback" == command) + { + gAgentPilot.stopPlayback(); + } + else if ("start record" == command) + { + gAgentPilot.startRecord(); + } + else if ("stop record" == command) + { + gAgentPilot.stopRecord(); + } + + return true; + } }; @@ -2253,20 +2253,20 @@ class LLAdvancedAgentPilot : public view_listener_t class LLAdvancedToggleAgentPilotLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgentPilot.setLoop(!gAgentPilot.getLoop()); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgentPilot.setLoop(!gAgentPilot.getLoop()); + return true; + } }; class LLAdvancedCheckAgentPilotLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentPilot.getLoop(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgentPilot.getLoop(); + return new_value; + } }; @@ -2277,20 +2277,20 @@ class LLAdvancedCheckAgentPilotLoop : public view_listener_t class LLAdvancedToggleShowObjectUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gShowObjectUpdates = !(gShowObjectUpdates); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gShowObjectUpdates = !(gShowObjectUpdates); + return true; + } }; class LLAdvancedCheckShowObjectUpdates : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gShowObjectUpdates; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gShowObjectUpdates; + return new_value; + } }; @@ -2302,11 +2302,11 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t class LLAdvancedCompressImage : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_compress_image(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_compress_image(NULL); + return true; + } }; @@ -2332,11 +2332,11 @@ class LLAdvancedCompressFileTest : public view_listener_t class LLAdvancedShowDebugSettings : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("settings_debug",userdata); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("settings_debug",userdata); + return true; + } }; @@ -2347,40 +2347,40 @@ class LLAdvancedShowDebugSettings : public view_listener_t class LLAdvancedEnableViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // Don't enable in god mode since the admin menu is shown anyway. - // Only enable if the user has set the appropriate debug setting. - bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // Don't enable in god mode since the admin menu is shown anyway. + // Only enable if the user has set the appropriate debug setting. + bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); + return new_value; + } }; class LLAdvancedToggleViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_admin_override_toggle(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_admin_override_toggle(NULL); + return true; + } }; class LLAdvancedToggleVisualLeakDetector : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_visual_leak_detector_toggle(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_visual_leak_detector_toggle(NULL); + return true; + } }; class LLAdvancedCheckViewAdminOptions : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); + return new_value; + } }; ////////////////// @@ -2390,20 +2390,20 @@ class LLAdvancedCheckViewAdminOptions : public view_listener_t class LLAdvancedRequestAdminStatus : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_god_mode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_god_mode(NULL); + return true; + } }; class LLAdvancedLeaveAdminStatus : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_leave_god_mode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_leave_god_mode(NULL); + return true; + } }; ////////////////////////// @@ -2412,20 +2412,20 @@ class LLAdvancedLeaveAdminStatus : public view_listener_t class LLAdvancedForceErrorBreakpoint : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_breakpoint(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_breakpoint(NULL); + return true; + } }; class LLAdvancedForceErrorLlerror : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_llerror(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_llerror(NULL); + return true; + } }; class LLAdvancedForceErrorLlerrorMsg: public view_listener_t @@ -2439,11 +2439,11 @@ class LLAdvancedForceErrorLlerrorMsg: public view_listener_t class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_bad_memory_access(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_bad_memory_access(NULL); + return true; + } }; class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t @@ -2464,20 +2464,20 @@ class LLAdvancedForceErrorBadMemoryAccessCoro : public view_listener_t class LLAdvancedForceErrorInfiniteLoop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_infinite_loop(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_infinite_loop(NULL); + return true; + } }; class LLAdvancedForceErrorSoftwareException : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_software_exception(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_software_exception(NULL); + return true; + } }; class LLAdvancedForceOSException: public view_listener_t @@ -2507,11 +2507,11 @@ class LLAdvancedForceErrorSoftwareExceptionCoro : public view_listener_t class LLAdvancedForceErrorDriverCrash : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_error_driver_crash(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_error_driver_crash(NULL); + return true; + } }; class LLAdvancedForceErrorCoroutineCrash : public view_listener_t @@ -2534,10 +2534,10 @@ class LLAdvancedForceErrorThreadCrash : public view_listener_t class LLAdvancedForceErrorDisconnectViewer : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_disconnect_viewer(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + handle_disconnect_viewer(NULL); + return true; } }; @@ -2546,29 +2546,29 @@ class LLAdvancedForceErrorDisconnectViewer : public view_listener_t class LLAdvancedHandleToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_toggle_hacked_godmode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_toggle_hacked_godmode(NULL); + return true; + } }; class LLAdvancedCheckToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - check_toggle_hacked_godmode(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + check_toggle_hacked_godmode(NULL); + return true; + } }; class LLAdvancedEnableToggleHackedGodmode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_toggle_hacked_godmode(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_toggle_hacked_godmode(NULL); + return new_value; + } }; #endif @@ -2585,21 +2585,21 @@ class LLAdvancedEnableToggleHackedGodmode : public view_listener_t class LLDevelopCheckLoggingLevel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 level = userdata.asInteger(); - return (static_cast(level) == LLError::getDefaultLevel()); - } + bool handleEvent(const LLSD& userdata) + { + U32 level = userdata.asInteger(); + return (static_cast(level) == LLError::getDefaultLevel()); + } }; class LLDevelopSetLoggingLevel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - U32 level = userdata.asInteger(); - LLError::setDefaultLevel(static_cast(level)); - return true; - } + bool handleEvent(const LLSD& userdata) + { + U32 level = userdata.asInteger(); + LLError::setDefaultLevel(static_cast(level)); + return true; + } }; ////////////////// @@ -2609,100 +2609,100 @@ class LLDevelopSetLoggingLevel : public view_listener_t // Admin > Object class LLAdminForceTakeCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - force_take_copy(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + force_take_copy(NULL); + return true; + } }; class LLAdminHandleObjectOwnerSelf : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_self(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_owner_self(NULL); + return true; + } }; class LLAdminHandleObjectOwnerPermissive : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_permissive(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_owner_permissive(NULL); + return true; + } }; class LLAdminHandleForceDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_delete(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_delete(NULL); + return true; + } }; class LLAdminHandleObjectLock : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_lock(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_lock(NULL); + return true; + } }; class LLAdminHandleObjectAssetIDs: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_object_asset_ids(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_object_asset_ids(NULL); + return true; + } }; //Admin >Parcel class LLAdminHandleForceParcelOwnerToMe: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_owner_to_me(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_owner_to_me(NULL); + return true; + } }; class LLAdminHandleForceParcelToContent: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_to_content(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_to_content(NULL); + return true; + } }; class LLAdminHandleClaimPublicLand: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_claim_public_land(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_claim_public_land(NULL); + return true; + } }; // Admin > Region class LLAdminHandleRegionDumpTempAssetData: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_region_dump_temp_asset_data(NULL); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_region_dump_temp_asset_data(NULL); + return true; + } }; //Admin (Top Level) class LLAdminOnSaveState: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPanelRegionTools::onSaveState(NULL); - return true; + bool handleEvent(const LLSD& userdata) + { + LLPanelRegionTools::onSaveState(NULL); + return true; } }; @@ -2712,38 +2712,38 @@ class LLAdminOnSaveState: public view_listener_t //----------------------------------------------------------------------------- void cleanup_menus() { - delete gMenuParcelObserver; - gMenuParcelObserver = NULL; + delete gMenuParcelObserver; + gMenuParcelObserver = NULL; - delete gMenuAvatarSelf; - gMenuAvatarSelf = NULL; + delete gMenuAvatarSelf; + gMenuAvatarSelf = NULL; - delete gMenuAvatarOther; - gMenuAvatarOther = NULL; + delete gMenuAvatarOther; + gMenuAvatarOther = NULL; - delete gMenuObject; - gMenuObject = NULL; + delete gMenuObject; + gMenuObject = NULL; - delete gMenuAttachmentSelf; - gMenuAttachmentSelf = NULL; + delete gMenuAttachmentSelf; + gMenuAttachmentSelf = NULL; - delete gMenuAttachmentOther; - gMenuAttachmentSelf = NULL; + delete gMenuAttachmentOther; + gMenuAttachmentSelf = NULL; - delete gMenuLand; - gMenuLand = NULL; + delete gMenuLand; + gMenuLand = NULL; - delete gMenuMuteParticle; - gMenuMuteParticle = NULL; + delete gMenuMuteParticle; + gMenuMuteParticle = NULL; - delete gMenuBarView; - gMenuBarView = NULL; + delete gMenuBarView; + gMenuBarView = NULL; - delete gPopupMenuView; - gPopupMenuView = NULL; + delete gPopupMenuView; + gPopupMenuView = NULL; - delete gMenuHolder; - gMenuHolder = NULL; + delete gMenuHolder; + gMenuHolder = NULL; } //----------------------------------------------------------------------------- @@ -2752,40 +2752,40 @@ void cleanup_menus() class LLObjectReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReporter::showFromObject(objectp->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReporter::showFromObject(objectp->getID()); + } + return true; + } }; // Enabled it you clicked an object class LLObjectEnableReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; + return new_value; + } }; void handle_object_touch() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return; - LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLPickInfo pick = LLToolPie::getInstance()->getPick(); - // *NOTE: Hope the packets arrive safely and in order or else - // there will be some problems. - // *TODO: Just fix this bad assumption. - send_ObjectGrab_message(object, pick, LLVector3::zero); - send_ObjectDeGrab_message(object, pick); + // *NOTE: Hope the packets arrive safely and in order or else + // there will be some problems. + // *TODO: Just fix this bad assumption. + send_ObjectGrab_message(object, pick, LLVector3::zero); + send_ObjectDeGrab_message(object, pick); } void handle_object_show_original() @@ -2818,75 +2818,75 @@ void handle_object_show_original() static void init_default_item_label(LLUICtrl* ctrl) { - const std::string& item_name = ctrl->getName(); - boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); - if (it == sDefaultItemLabels.end()) - { - // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value - // (doesn't seem to matter much ATM). - LLStringExplicit default_label = ctrl->getValue().asString(); - if (!default_label.empty()) - { - sDefaultItemLabels.insert(std::pair(item_name, default_label)); - } - } + const std::string& item_name = ctrl->getName(); + boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); + if (it == sDefaultItemLabels.end()) + { + // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value + // (doesn't seem to matter much ATM). + LLStringExplicit default_label = ctrl->getValue().asString(); + if (!default_label.empty()) + { + sDefaultItemLabels.insert(std::pair(item_name, default_label)); + } + } } static LLStringExplicit get_default_item_label(const std::string& item_name) { - LLStringExplicit res(""); - boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); - if (it != sDefaultItemLabels.end()) - { - res = it->second; - } + LLStringExplicit res(""); + boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); + if (it != sDefaultItemLabels.end()) + { + res = it->second; + } - return res; + return res; } bool enable_object_touch(LLUICtrl* ctrl) { - bool new_value = false; - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (obj) - { - LLViewerObject* parent = (LLViewerObject*)obj->getParent(); - new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); - } + bool new_value = false; + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + LLViewerObject* parent = (LLViewerObject*)obj->getParent(); + new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); + } - init_default_item_label(ctrl); + init_default_item_label(ctrl); - // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mTouchName.empty()) - { - ctrl->setValue(node->mTouchName); - } - else - { - ctrl->setValue(get_default_item_label(ctrl->getName())); - } + // Update label based on the node touch name if available. + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mTouchName.empty()) + { + ctrl->setValue(node->mTouchName); + } + else + { + ctrl->setValue(get_default_item_label(ctrl->getName())); + } - return new_value; + return new_value; }; //void label_touch(std::string& label, void*) //{ -// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); -// if (node && node->mValid && !node->mTouchName.empty()) -// { -// label.assign(node->mTouchName); -// } -// else -// { -// label.assign("Touch"); -// } +// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); +// if (node && node->mValid && !node->mTouchName.empty()) +// { +// label.assign(node->mTouchName); +// } +// else +// { +// label.assign("Touch"); +// } //} void handle_object_open() { - LLFloaterReg::showInstance("openobject"); + LLFloaterReg::showInstance("openobject"); } bool enable_object_inspect() @@ -2941,67 +2941,67 @@ bool enable_object_edit_gltf_material() bool enable_object_open() { - // Look for contents in root object, which is all the LLFloaterOpenObject - // understands. - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!obj) return false; + // Look for contents in root object, which is all the LLFloaterOpenObject + // understands. + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!obj) return false; - LLViewerObject* root = obj->getRootEdit(); - if (!root) return false; + LLViewerObject* root = obj->getRootEdit(); + if (!root) return false; - return root->allowOpen(); + return root->allowOpen(); } class LLViewJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_toggle_flycam(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_toggle_flycam(); + return true; + } }; class LLViewCheckJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); + return new_value; + } }; void handle_toggle_flycam() { - LLViewerJoystick::getInstance()->toggleFlycam(); + LLViewerJoystick::getInstance()->toggleFlycam(); } class LLObjectBuild : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - - // Could be first use - //LLFirstUse::useBuild(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gAgentCamera.cameraZoomIn(0.666f); + gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } + + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + + // Could be first use + //LLFirstUse::useBuild(); + return true; + } }; void update_camera() @@ -3040,17 +3040,17 @@ void handle_object_edit() { update_camera(); - LLFloaterReg::showInstance("build"); - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); - - LLViewerJoystick::getInstance()->moveObjects(true); - LLViewerJoystick::getInstance()->setNeedsReset(true); - - // Could be first use - //LLFirstUse::useBuild(); - return; + LLFloaterReg::showInstance("build"); + + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); + + LLViewerJoystick::getInstance()->moveObjects(true); + LLViewerJoystick::getInstance()->setNeedsReset(true); + + // Could be first use + //LLFirstUse::useBuild(); + return; } void handle_object_edit_gltf_material() @@ -3072,68 +3072,68 @@ void handle_object_edit_gltf_material() void handle_attachment_edit(const LLUUID& inv_item_id) { - if (isAgentAvatarValid()) - { - if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) - { - LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); + if (isAgentAvatarValid()) + { + if (LLViewerObject* attached_obj = gAgentAvatarp->getWornAttachment(inv_item_id)) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(attached_obj); - handle_object_edit(); - } - } + handle_object_edit(); + } + } } void handle_attachment_touch(const LLUUID& inv_item_id) { - if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) - { - if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) - { - LLSelectMgr::getInstance()->deselectAll(); - - LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); - if (!LLToolMgr::getInstance()->inBuildMode()) - { - struct SetTransient : public LLSelectedNodeFunctor - { - bool apply(LLSelectNode* node) - { - node->setTransient(TRUE); - return true; - } - } f; - sel->applyToNodes(&f); - } - - handle_object_touch(); - } - } + if ( (isAgentAvatarValid()) && (enable_attachment_touch(inv_item_id)) ) + { + if (LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id))) + { + LLSelectMgr::getInstance()->deselectAll(); + + LLObjectSelectionHandle sel = LLSelectMgr::getInstance()->selectObjectAndFamily(attach_obj); + if (!LLToolMgr::getInstance()->inBuildMode()) + { + struct SetTransient : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + node->setTransient(TRUE); + return true; + } + } f; + sel->applyToNodes(&f); + } + + handle_object_touch(); + } + } } bool enable_attachment_touch(const LLUUID& inv_item_id) { - if (isAgentAvatarValid()) - { - const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); - return (attach_obj) && (attach_obj->flagHandleTouch()); - } - return false; + if (isAgentAvatarValid()) + { + const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); + return (attach_obj) && (attach_obj->flagHandleTouch()); + } + return false; } void handle_object_inspect() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* selected_objectp = selection->getFirstRootObject(); - if (selected_objectp) - { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* selected_objectp = selection->getFirstRootObject(); + if (selected_objectp) + { LLFloaterReg::showInstance("task_properties"); - } - - /* - // Old floater properties - LLFloaterReg::showInstance("inspect", LLSD()); - */ + } + + /* + // Old floater properties + LLFloaterReg::showInstance("inspect", LLSD()); + */ } //--------------------------------------------------------------------------- @@ -3141,133 +3141,133 @@ void handle_object_inspect() //--------------------------------------------------------------------------- class LLLandBuild : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerParcelMgr::getInstance()->deselectLand(); + bool handleEvent(const LLSD& userdata) + { + LLViewerParcelMgr::getInstance()->deselectLand(); - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - // otherwise just move focus - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } + if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gAgentCamera.cameraZoomIn(0.666f); + gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + // otherwise just move focus + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - // Could be first use - //LLFirstUse::useBuild(); - return true; - } + // Could be first use + //LLFirstUse::useBuild(); + return true; + } }; class LLLandBuyPass : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPanelLandGeneral::onClickBuyPass((void *)FALSE); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLPanelLandGeneral::onClickBuyPass((void *)FALSE); + return true; + } }; class LLLandEnableBuyPass : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); + return new_value; + } }; // BUG: Should really check if CLICK POINT is in a parcel where you can build. BOOL enable_land_build(void*) { - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; + if (gAgent.isGodlike()) return TRUE; + if (gAgent.inPrelude()) return FALSE; - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; + BOOL can_build = FALSE; + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel) + { + can_build = agent_parcel->getAllowModify(); + } + return can_build; } // BUG: Should really check if OBJECT is in a parcel where you can build. BOOL enable_object_build(void*) { - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; + if (gAgent.isGodlike()) return TRUE; + if (gAgent.inPrelude()) return FALSE; - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; + BOOL can_build = FALSE; + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel) + { + can_build = agent_parcel->getAllowModify(); + } + return can_build; } bool enable_object_edit() { - if (!isAgentAvatarValid()) return false; - - // *HACK: The new "prelude" Help Islands have a build sandbox area, - // so users need the Edit and Create pie menu options when they are - // there. Eventually this needs to be replaced with code that only - // lets you edit objects if you have permission to do so (edit perms, - // group edit, god). See also lltoolbar.cpp. JC - bool enable = false; - if (gAgent.inPrelude()) - { - enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() - || LLSelectMgr::getInstance()->getSelection()->isAttachment(); - } - else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) - { - enable = true; - } - - return enable; + if (!isAgentAvatarValid()) return false; + + // *HACK: The new "prelude" Help Islands have a build sandbox area, + // so users need the Edit and Create pie menu options when they are + // there. Eventually this needs to be replaced with code that only + // lets you edit objects if you have permission to do so (edit perms, + // group edit, god). See also lltoolbar.cpp. JC + bool enable = false; + if (gAgent.inPrelude()) + { + enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() + || LLSelectMgr::getInstance()->getSelection()->isAttachment(); + } + else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) + { + enable = true; + } + + return enable; } bool enable_mute_particle() { - const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); - return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID(); + return pick.mParticleOwnerID != LLUUID::null && pick.mParticleOwnerID != gAgent.getID(); } // mutually exclusive - show either edit option or build in menu bool enable_object_build() { - return !enable_object_edit(); + return !enable_object_edit(); } bool enable_object_select_in_pathfinding_linksets() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); } bool visible_object_select_in_pathfinding_linksets() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); } bool enable_object_select_in_pathfinding_characters() { - return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); + return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } bool enable_os_exception() @@ -3281,40 +3281,40 @@ bool enable_os_exception() class LLSelfRemoveAllAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); + return true; + } }; class LLSelfEnableRemoveAllAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - if (isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getNumObjects() > 0) - { - new_value = true; - break; - } - } - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = false; + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getNumObjects() > 0) + { + new_value = true; + break; + } + } + } + return new_value; + } }; BOOL enable_has_attachments(void*) { - return FALSE; + return FALSE; } //--------------------------------------------------------------------------- @@ -3322,229 +3322,229 @@ BOOL enable_has_attachments(void*) //--------------------------------------------------------------------------- //void handle_follow(void *userdata) //{ -// // follow a given avatar by ID -// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if (objectp) -// { -// gAgent.startFollowPilot(objectp->getID()); -// } +// // follow a given avatar by ID +// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +// if (objectp) +// { +// gAgent.startFollowPilot(objectp->getID()); +// } //} bool enable_object_mute() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && - !LLMuteList::getInstance()->isMuted(object->getID()); - } + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + // It's an avatar + LLNameValue *lastname = avatar->getNVPair("LastName"); + bool is_linden = + lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); + bool is_self = avatar->isSelf(); + return !is_linden && !is_self; + } + else + { + // Just a regular object + return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && + !LLMuteList::getInstance()->isMuted(object->getID()); + } } bool enable_object_unmute() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && - LLMuteList::getInstance()->isMuted(object->getID());; - } + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + // It's an avatar + LLNameValue *lastname = avatar->getNVPair("LastName"); + bool is_linden = + lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); + bool is_self = avatar->isSelf(); + return !is_linden && !is_self; + } + else + { + // Just a regular object + return LLSelectMgr::getInstance()->getSelection()->contains( object, SELECT_ALL_TES ) && + LLMuteList::getInstance()->isMuted(object->getID());; + } } // 0 = normal, 1 = always, 2 = never class LLAvatarCheckImpostorMode : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (!avatar) return false; - - U32 mode = userdata.asInteger(); - switch (mode) - { - case 0: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); - case 1: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); - case 2: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (!avatar) return false; + + U32 mode = userdata.asInteger(); + switch (mode) + { + case 0: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); + case 1: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); + case 2: + return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); case 4: return (avatar->getVisualMuteSettings() != LLVOAvatar::AV_RENDER_NORMALLY); - default: - return false; - } - } // handleEvent() + default: + return false; + } + } // handleEvent() }; // 0 = normal, 1 = always, 2 = never class LLAvatarSetImpostorMode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (!avatar) return false; - - U32 mode = userdata.asInteger(); - switch (mode) - { - case 0: - avatar->setVisualMuteSettings(LLVOAvatar::AV_RENDER_NORMALLY); - break; - case 1: - avatar->setVisualMuteSettings(LLVOAvatar::AV_DO_NOT_RENDER); - break; - case 2: - avatar->setVisualMuteSettings(LLVOAvatar::AV_ALWAYS_RENDER); - break; - default: - return false; - } - - LLVOAvatar::cullAvatarsByPixelArea(); - return true; - } // handleEvent() + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return false; + + LLVOAvatar* avatar = find_avatar_from_object(object); + if (!avatar) return false; + + U32 mode = userdata.asInteger(); + switch (mode) + { + case 0: + avatar->setVisualMuteSettings(LLVOAvatar::AV_RENDER_NORMALLY); + break; + case 1: + avatar->setVisualMuteSettings(LLVOAvatar::AV_DO_NOT_RENDER); + break; + case 2: + avatar->setVisualMuteSettings(LLVOAvatar::AV_ALWAYS_RENDER); + break; + default: + return false; + } + + LLVOAvatar::cullAvatarsByPixelArea(); + return true; + } // handleEvent() }; class LLObjectMute : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return true; - - LLUUID id; - std::string name; - LLMute::EType type; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - avatar->mNeedsImpostorUpdate = TRUE; - avatar->mLastImpostorUpdateReason = 9; - - id = avatar->getID(); - - LLNameValue *firstname = avatar->getNVPair("FirstName"); - LLNameValue *lastname = avatar->getNVPair("LastName"); - if (firstname && lastname) - { - name = LLCacheName::buildFullName( - firstname->getString(), lastname->getString()); - } - - type = LLMute::AGENT; - } - else - { - // it's an object - id = object->getID(); - - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node) - { - name = node->mName; - } - - type = LLMute::OBJECT; - } - - LLMute mute(id, name, type); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return true; + + LLUUID id; + std::string name; + LLMute::EType type; + LLVOAvatar* avatar = find_avatar_from_object(object); + if (avatar) + { + avatar->mNeedsImpostorUpdate = TRUE; + avatar->mLastImpostorUpdateReason = 9; + + id = avatar->getID(); + + LLNameValue *firstname = avatar->getNVPair("FirstName"); + LLNameValue *lastname = avatar->getNVPair("LastName"); + if (firstname && lastname) + { + name = LLCacheName::buildFullName( + firstname->getString(), lastname->getString()); + } + + type = LLMute::AGENT; + } + else + { + // it's an object + id = object->getID(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node) + { + name = node->mName; + } + + type = LLMute::OBJECT; + } + + LLMute mute(id, name, type); + if (LLMuteList::getInstance()->isMuted(mute.mID)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + + return true; + } }; bool handle_go_to() { - // try simulator autopilot - std::vector strings; - std::string val; - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - val = llformat("%g", pos.mdV[VX]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); - strings.push_back(val); - send_generic_message("autopilot", strings); - - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else - { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); - } - - // Could be first use - //LLFirstUse::useGoTo(); - return true; + // try simulator autopilot + std::vector strings; + std::string val; + LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; + val = llformat("%g", pos.mdV[VX]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VY]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VZ]); + strings.push_back(val); + send_generic_message("autopilot", strings); + + LLViewerParcelMgr::getInstance()->deselectLand(); + + if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) + { + gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); + } + else + { + // Snap camera back to behind avatar + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); + } + + // Could be first use + //LLFirstUse::useGoTo(); + return true; } class LLGoToObject : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return handle_go_to(); - } + bool handleEvent(const LLSD& userdata) + { + return handle_go_to(); + } }; class LLAvatarReportAbuse : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLFloaterReporter::showFromObject(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLFloaterReporter::showFromObject(avatar->getID()); + } + return true; + } }; @@ -3553,230 +3553,230 @@ class LLAvatarReportAbuse : public view_listener_t //--------------------------------------------------------------------------- bool callback_freeze(const LLSD& notification, const LLSD& response) { - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option || 1 == option) - { - U32 flags = 0x0; - if (1 == option) - { - // unfreeze - flags |= 0x1; - } - - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - msg->newMessage("FreezeUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; -} + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option || 1 == option) + { + U32 flags = 0x0; + if (1 == option) + { + // unfreeze + flags |= 0x1; + } + + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + msg->newMessage("FreezeUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + return false; +} void handle_avatar_freeze(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - std::string fullname = avatar->getFullname(); - LLSD payload; - payload["avatar_id"] = avatar->getID(); - - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("FreezeAvatarFullname", - args, - payload, - callback_freeze); - } - else - { - LLNotificationsUtil::add("FreezeAvatar", - LLSD(), - payload, - callback_freeze); - } - } + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + + if( avatar ) + { + std::string fullname = avatar->getFullname(); + LLSD payload; + payload["avatar_id"] = avatar->getID(); + + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("FreezeAvatarFullname", + args, + payload, + callback_freeze); + } + else + { + LLNotificationsUtil::add("FreezeAvatar", + LLSD(), + payload, + callback_freeze); + } + } } class LLAvatarVisibleDebug : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.isGodlike(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.isGodlike(); + } }; class LLAvatarDebug : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if( avatar ) - { - if (avatar->isSelf()) - { - ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); - } - LL_INFOS() << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << LL_ENDL; - std::vector strings; - strings.push_back(avatar->getID().asString()); - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); - LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if( avatar ) + { + if (avatar->isSelf()) + { + ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); + } + LL_INFOS() << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << LL_ENDL; + std::vector strings; + strings.push_back(avatar->getID().asString()); + LLUUID invoice; + send_generic_message("dumptempassetdata", strings, invoice); + LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); + } + return true; + } }; bool callback_eject(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (2 == option) - { - // Cancel button. - return false; - } - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); - - if (0 == option) - { - // Eject button - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x0; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - else if (ban_enabled) - { - // This is tricky. It is similar to say if it is not an 'Eject' button, - // and it is also not an 'Cancle' button, and ban_enabled==ture, - // it should be the 'Eject and Ban' button. - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x1; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (2 == option) + { + // Cancel button. + return false; + } + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); + + if (0 == option) + { + // Eject button + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + U32 flags = 0x0; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID() ); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + else if (ban_enabled) + { + // This is tricky. It is similar to say if it is not an 'Eject' button, + // and it is also not an 'Cancle' button, and ban_enabled==ture, + // it should be the 'Eject and Ban' button. + LLMessageSystem* msg = gMessageSystem; + LLViewerObject* avatar = gObjectList.findObject(avatar_id); + + if (avatar) + { + U32 flags = 0x1; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID() ); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id ); + msg->addU32("Flags", flags ); + msg->sendReliable( avatar->getRegion()->getHost() ); + } + } + return false; } void handle_avatar_eject(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - LLSD payload; - payload["avatar_id"] = avatar->getID(); - std::string fullname = avatar->getFullname(); - - const LLVector3d& pos = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); - - if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) - { + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + + if( avatar ) + { + LLSD payload; + payload["avatar_id"] = avatar->getID(); + std::string fullname = avatar->getFullname(); + + const LLVector3d& pos = avatar->getPositionGlobal(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); + + if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) + { payload["ban_enabled"] = true; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullname", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarFullname", - LLSD(), - payload, - callback_eject); - } - } - else - { + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("EjectAvatarFullname", + args, + payload, + callback_eject); + } + else + { + LLNotificationsUtil::add("EjectAvatarFullname", + LLSD(), + payload, + callback_eject); + } + } + else + { payload["ban_enabled"] = false; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullnameNoBan", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarNoBan", - LLSD(), - payload, - callback_eject); - } - } - } + if (!fullname.empty()) + { + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotificationsUtil::add("EjectAvatarFullnameNoBan", + args, + payload, + callback_eject); + } + else + { + LLNotificationsUtil::add("EjectAvatarNoBan", + LLSD(), + payload, + callback_eject); + } + } + } } bool my_profile_visible() { - LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); - return floaterp && floaterp->isInVisibleChain(); + LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); + return floaterp && floaterp->isInVisibleChain(); } bool picks_tab_visible() @@ -3786,192 +3786,192 @@ bool picks_tab_visible() bool enable_freeze_eject(const LLSD& avatar_id) { - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - if (!avatar) return false; - - // Gods can always freeze - if (gAgent.isGodlike()) return true; - - // Estate owners / managers can freeze - // Parcel owners can also freeze - const LLVector3& pos = avatar->getPositionRegion(); - const LLVector3d& pos_global = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); - LLViewerRegion* region = avatar->getRegion(); - if (!region) return false; - - bool new_value = region->isOwnedSelf(pos); - if (!new_value || region->isOwnedGroup(pos)) - { - new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); - } - return new_value; + // Use avatar_id if available, otherwise default to right-click avatar + LLVOAvatar* avatar = NULL; + if (avatar_id.asUUID().notNull()) + { + avatar = find_avatar_from_object(avatar_id.asUUID()); + } + else + { + avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + } + if (!avatar) return false; + + // Gods can always freeze + if (gAgent.isGodlike()) return true; + + // Estate owners / managers can freeze + // Parcel owners can also freeze + const LLVector3& pos = avatar->getPositionRegion(); + const LLVector3d& pos_global = avatar->getPositionGlobal(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); + LLViewerRegion* region = avatar->getRegion(); + if (!region) return false; + + bool new_value = region->isOwnedSelf(pos); + if (!new_value || region->isOwnedGroup(pos)) + { + new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); + } + return new_value; } bool callback_leave_group(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_LeaveGroupRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); - gAgent.sendReliableMessage(); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_LeaveGroupRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_GroupData); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); + gAgent.sendReliableMessage(); + } + return false; } void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt) { - LLAggregatePermissions::EValue val = ag_perm.getValue(bit); - std::string buffer; - switch(val) - { - case LLAggregatePermissions::AP_NONE: - buffer = llformat( "* %s None\n", txt); - break; - case LLAggregatePermissions::AP_SOME: - buffer = llformat( "* %s Some\n", txt); - break; - case LLAggregatePermissions::AP_ALL: - buffer = llformat( "* %s All\n", txt); - break; - case LLAggregatePermissions::AP_EMPTY: - default: - break; - } - string.append(buffer); + LLAggregatePermissions::EValue val = ag_perm.getValue(bit); + std::string buffer; + switch(val) + { + case LLAggregatePermissions::AP_NONE: + buffer = llformat( "* %s None\n", txt); + break; + case LLAggregatePermissions::AP_SOME: + buffer = llformat( "* %s Some\n", txt); + break; + case LLAggregatePermissions::AP_ALL: + buffer = llformat( "* %s All\n", txt); + break; + case LLAggregatePermissions::AP_EMPTY: + default: + break; + } + string.append(buffer); } bool enable_buy_object() { // In order to buy, there must only be 1 purchaseable object in // the selection manager. - if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; + if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; LLViewerObject* obj = NULL; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node) + if(node) { obj = node->getObject(); if(!obj) return false; - if( for_sale_selection(node) ) - { - // *NOTE: Is this needed? This checks to see if anyone owns the - // object, dating back to when we had "public" objects owned by - // no one. JC - if(obj->permAnyOwner()) return true; - } + if( for_sale_selection(node) ) + { + // *NOTE: Is this needed? This checks to see if anyone owns the + // object, dating back to when we had "public" objects owned by + // no one. JC + if(obj->permAnyOwner()) return true; + } } - return false; + return false; } // Note: This will only work if the selected object's data has been // received by the viewer and cached in the selection manager. void handle_buy_object(LLSaleInfo sale_info) { - if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) - { - LLNotificationsUtil::add("UnableToBuyWhileDownloading"); - return; - } + if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) + { + LLNotificationsUtil::add("UnableToBuyWhileDownloading"); + return; + } - LLUUID owner_id; - std::string owner_name; - BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); - if (!owners_identical) - { - LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); - return; - } + LLUUID owner_id; + std::string owner_name; + BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + if (!owners_identical) + { + LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); + return; + } - LLPermissions perm; - BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); - LLAggregatePermissions ag_perm; - valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); - if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) - { - LLNotificationsUtil::add("ObjectNotForSale"); - return; - } + LLPermissions perm; + BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); + LLAggregatePermissions ag_perm; + valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); + if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) + { + LLNotificationsUtil::add("ObjectNotForSale"); + return; + } - LLFloaterBuy::show(sale_info); + LLFloaterBuy::show(sale_info); } void handle_buy_contents(LLSaleInfo sale_info) { - LLFloaterBuyContents::show(sale_info); + LLFloaterBuyContents::show(sale_info); } void handle_region_dump_temp_asset_data(void*) { - LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; - std::vector strings; - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); + LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; + std::vector strings; + LLUUID invoice; + send_generic_message("dumptempassetdata", strings, invoice); } void handle_region_clear_temp_asset_data(void*) { - LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; - std::vector strings; - LLUUID invoice; - send_generic_message("cleartempassetdata", strings, invoice); + LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; + std::vector strings; + LLUUID invoice; + send_generic_message("cleartempassetdata", strings, invoice); } void handle_region_dump_settings(void*) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; - LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; + } } void handle_dump_group_info(void *) { - gAgent.dumpGroupInfo(); + gAgent.dumpGroupInfo(); } void handle_dump_capabilities_info(void *) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->logActiveCapabilities(); - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + regionp->logActiveCapabilities(); + } } void handle_dump_region_object_cache(void*) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->dumpCache(); - } + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + regionp->dumpCache(); + } } void handle_reset_interest_lists(void *) @@ -3992,18 +3992,18 @@ void handle_reset_interest_lists(void *) void handle_dump_focus() { - LLUICtrl *ctrl = dynamic_cast(gFocusMgr.getKeyboardFocus()); + LLUICtrl *ctrl = dynamic_cast(gFocusMgr.getKeyboardFocus()); - LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; + LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; } class LLSelfStandUp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.standUp(); + return true; + } }; bool enable_standup_self() @@ -4024,202 +4024,202 @@ class LLSelfSitDown : public view_listener_t bool show_sitdown_self() { - return isAgentAvatarValid() && !gAgentAvatarp->isSitting(); + return isAgentAvatarValid() && !gAgentAvatarp->isSitting(); } bool enable_sitdown_self() { - return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); + return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } class LLSelfToggleSitStand : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (isAgentAvatarValid()) - { - if (gAgentAvatarp->isSitting()) - { - gAgent.standUp(); - } - else - { - gAgent.sitDown(); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (isAgentAvatarValid()) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + } + else + { + gAgent.sitDown(); + } + } + return true; + } }; bool enable_sit_stand() { - return enable_sitdown_self() || enable_standup_self(); + return enable_sitdown_self() || enable_standup_self(); } bool enable_fly_land() { - return gAgent.getFlying() || LLAgent::enableFlying(); + return gAgent.getFlying() || LLAgent::enableFlying(); } class LLCheckPanelPeopleTab : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string panel_name = userdata.asString(); - LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); - if(panel && panel->isInVisibleChain()) - { - return true; - } - return false; - } + LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); + if(panel && panel->isInVisibleChain()) + { + return true; + } + return false; + } }; // Toggle one of "People" panel tabs in side tray. class LLTogglePanelPeopleTab : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); - - LLSD param; - param["people_panel_tab_name"] = panel_name; - - if ( panel_name == "friends_panel" - || panel_name == "groups_panel" - || panel_name == "nearby_panel" - || panel_name == "blocked_panel") - { - return togglePeoplePanel(panel_name, param); - } - else - { - return false; - } - } - - static bool togglePeoplePanel(const std::string& panel_name, const LLSD& param) - { - LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); - if(!panel) - return false; - - if (panel->isInVisibleChain()) - { - LLFloaterReg::hideInstance("people"); - } - else - { - LLFloaterSidePanelContainer::showPanel("people", "panel_people", param) ; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string panel_name = userdata.asString(); + + LLSD param; + param["people_panel_tab_name"] = panel_name; + + if ( panel_name == "friends_panel" + || panel_name == "groups_panel" + || panel_name == "nearby_panel" + || panel_name == "blocked_panel") + { + return togglePeoplePanel(panel_name, param); + } + else + { + return false; + } + } + + static bool togglePeoplePanel(const std::string& panel_name, const LLSD& param) + { + LLPanel *panel = LLFloaterSidePanelContainer::getPanel("people", panel_name); + if(!panel) + return false; + + if (panel->isInVisibleChain()) + { + LLFloaterReg::hideInstance("people"); + } + else + { + LLFloaterSidePanelContainer::showPanel("people", "panel_people", param) ; + } + + return true; + } }; BOOL check_admin_override(void*) { - return gAgent.getAdminOverride(); + return gAgent.getAdminOverride(); } void handle_admin_override_toggle(void*) { - gAgent.setAdminOverride(!gAgent.getAdminOverride()); + gAgent.setAdminOverride(!gAgent.getAdminOverride()); - // The above may have affected which debug menus are visible - show_debug_menus(); + // The above may have affected which debug menus are visible + show_debug_menus(); } void handle_visual_leak_detector_toggle(void*) { - static bool vld_enabled = false; + static bool vld_enabled = false; - if ( vld_enabled ) - { + if ( vld_enabled ) + { #ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) + // only works for debug builds (hard coded into vld.h) #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDDisable(); + // start with Visual Leak Detector turned off + VLDDisable(); #endif // _DEBUG #endif // INCLUDE_VLD - vld_enabled = false; - } - else - { + vld_enabled = false; + } + else + { #ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) - #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDEnable(); - #endif // _DEBUG + // only works for debug builds (hard coded into vld.h) + #ifdef _DEBUG + // start with Visual Leak Detector turned off + VLDEnable(); + #endif // _DEBUG #endif // INCLUDE_VLD - vld_enabled = true; - }; + vld_enabled = true; + }; } void handle_god_mode(void*) { - gAgent.requestEnterGodMode(); + gAgent.requestEnterGodMode(); } void handle_leave_god_mode(void*) { - gAgent.requestLeaveGodMode(); + gAgent.requestLeaveGodMode(); } void set_god_level(U8 god_level) { - U8 old_god_level = gAgent.getGodLevel(); - gAgent.setGodLevel( god_level ); - LLViewerParcelMgr::getInstance()->notifyObservers(); + U8 old_god_level = gAgent.getGodLevel(); + gAgent.setGodLevel( god_level ); + LLViewerParcelMgr::getInstance()->notifyObservers(); - // God mode changes region visibility - LLWorldMap::getInstance()->reloadItems(true); + // God mode changes region visibility + LLWorldMap::getInstance()->reloadItems(true); - // inventory in items may change in god mode - gObjectList.dirtyAllObjectInventory(); + // inventory in items may change in god mode + gObjectList.dirtyAllObjectInventory(); if(gViewerWindow) { gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, LLGridManager::getInstance()->isInProductionGrid()); } - + LLSD args; - if(god_level > GOD_NOT) - { - args["LEVEL"] = llformat("%d",(S32)god_level); - LLNotificationsUtil::add("EnteringGodMode", args); - } - else - { - args["LEVEL"] = llformat("%d",(S32)old_god_level); - LLNotificationsUtil::add("LeavingGodMode", args); - } - - // changing god-level can affect which menus we see - show_debug_menus(); - - // changing god-level can invalidate search results - LLFloaterSearch *search = dynamic_cast(LLFloaterReg::getInstance("search")); - if (search) - { - search->godLevelChanged(god_level); - } + if(god_level > GOD_NOT) + { + args["LEVEL"] = llformat("%d",(S32)god_level); + LLNotificationsUtil::add("EnteringGodMode", args); + } + else + { + args["LEVEL"] = llformat("%d",(S32)old_god_level); + LLNotificationsUtil::add("LeavingGodMode", args); + } + + // changing god-level can affect which menus we see + show_debug_menus(); + + // changing god-level can invalidate search results + LLFloaterSearch *search = dynamic_cast(LLFloaterReg::getInstance("search")); + if (search) + { + search->godLevelChanged(god_level); + } } #ifdef TOGGLE_HACKED_GODLIKE_VIEWER void handle_toggle_hacked_godmode(void*) { - gHackGodmode = !gHackGodmode; - set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); + gHackGodmode = !gHackGodmode; + set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); } BOOL check_toggle_hacked_godmode(void*) { - return gHackGodmode; + return gHackGodmode; } bool enable_toggle_hacked_godmode(void*) @@ -4230,174 +4230,174 @@ bool enable_toggle_hacked_godmode(void*) void process_grant_godlike_powers(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) - { - U8 god_level; - msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); - set_god_level(god_level); - } - else - { - LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; - } + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) + { + U8 god_level; + msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); + set_god_level(god_level); + } + else + { + LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; + } } /* class LLHaveCallingcard : public LLInventoryCollectFunctor { public: - LLHaveCallingcard(const LLUUID& agent_id); - virtual ~LLHaveCallingcard() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL isThere() const { return mIsThere;} + LLHaveCallingcard(const LLUUID& agent_id); + virtual ~LLHaveCallingcard() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + BOOL isThere() const { return mIsThere;} protected: - LLUUID mID; - BOOL mIsThere; + LLUUID mID; + BOOL mIsThere; }; LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) : - mID(agent_id), - mIsThere(FALSE) + mID(agent_id), + mIsThere(FALSE) { } bool LLHaveCallingcard::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item) - { - if((item->getType() == LLAssetType::AT_CALLINGCARD) - && (item->getCreatorUUID() == mID)) - { - mIsThere = TRUE; - } - } - return FALSE; + LLInventoryItem* item) +{ + if(item) + { + if((item->getType() == LLAssetType::AT_CALLINGCARD) + && (item->getCreatorUUID() == mID)) + { + mIsThere = TRUE; + } + } + return FALSE; } */ BOOL is_agent_mappable(const LLUUID& agent_id) { - const LLRelationship* buddy_info = NULL; - bool is_friend = LLAvatarActions::isFriend(agent_id); + const LLRelationship* buddy_info = NULL; + bool is_friend = LLAvatarActions::isFriend(agent_id); - if (is_friend) - buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); + if (is_friend) + buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); - return (buddy_info && - buddy_info->isOnline() && - buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) - ); + return (buddy_info && + buddy_info->isOnline() && + buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) + ); } // Enable a menu item when you don't have someone's card. class LLAvatarEnableAddFriend : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); + return new_value; + } }; void request_friendship(const LLUUID& dest_id) { - LLViewerObject* dest = gObjectList.findObject(dest_id); - if(dest && dest->isAvatar()) - { - std::string full_name; - LLNameValue* nvfirst = dest->getNVPair("FirstName"); - LLNameValue* nvlast = dest->getNVPair("LastName"); - if(nvfirst && nvlast) - { - full_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - if (!full_name.empty()) - { - LLAvatarActions::requestFriendshipDialog(dest_id, full_name); - } - else - { - LLNotificationsUtil::add("CantOfferFriendship"); - } - } + LLViewerObject* dest = gObjectList.findObject(dest_id); + if(dest && dest->isAvatar()) + { + std::string full_name; + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if(nvfirst && nvlast) + { + full_name = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + } + if (!full_name.empty()) + { + LLAvatarActions::requestFriendshipDialog(dest_id, full_name); + } + else + { + LLNotificationsUtil::add("CantOfferFriendship"); + } + } } class LLEditEnableCustomizeAvatar : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentWearables.areWearablesLoaded(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgentWearables.areWearablesLoaded(); + return new_value; + } }; class LLEnableEditShape : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - } + bool handleEvent(const LLSD& userdata) + { + return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + } }; class LLEnableHoverHeight : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.getRegion() && gAgent.getRegion()->avatarHoverHeightEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.getRegion() && gAgent.getRegion()->avatarHoverHeightEnabled(); + } }; class LLEnableEditPhysics : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - return TRUE; - } + bool handleEvent(const LLSD& userdata) + { + //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + return TRUE; + } }; bool is_object_sittable() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (object && object->getPCode() == LL_PCODE_VOLUME) - { - return true; - } - else - { - return false; - } + if (object && object->getPCode() == LL_PCODE_VOLUME) + { + return true; + } + else + { + return false; + } } // only works on pie menu void handle_object_sit(LLViewerObject *object, const LLVector3 &offset) { - // get object selection offset + // get object selection offset - if (object && object->getPCode() == LL_PCODE_VOLUME) - { + if (object && object->getPCode() == LL_PCODE_VOLUME) + { - gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_TargetObject); - gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_TargetObject); + gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); + gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); - object->getRegion()->sendReliableMessage(); - } + object->getRegion()->sendReliableMessage(); + } } void handle_object_sit_or_stand() @@ -4432,12 +4432,12 @@ void handle_object_sit(const LLUUID& object_id) void near_sit_down_point(BOOL success, void *) { - if (success) - { - gAgent.setFlying(FALSE); - gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP); // might have been set by autopilot - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - } + if (success) + { + gAgent.setFlying(FALSE); + gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP); // might have been set by autopilot + gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + } } class LLLandSit : public view_listener_t @@ -4484,120 +4484,120 @@ void reset_view_final( BOOL proceed ); void handle_reset_view() { - if (gAgentCamera.cameraCustomizeAvatar()) - { - // switching to outfit selector should automagically save any currently edited wearable - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); - } - gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); - reset_view_final( TRUE ); - LLFloaterCamera::resetCameraMode(); + if (gAgentCamera.cameraCustomizeAvatar()) + { + // switching to outfit selector should automagically save any currently edited wearable + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); + } + gAgentCamera.setFocusOnAvatar(TRUE, FALSE, FALSE); + reset_view_final( TRUE ); + LLFloaterCamera::resetCameraMode(); } class LLViewResetView : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - handle_reset_view(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + handle_reset_view(); + return true; + } }; // Note: extra parameters allow this function to be called from dialog. -void reset_view_final( BOOL proceed ) +void reset_view_final( BOOL proceed ) { - if( !proceed ) - { - return; - } + if( !proceed ) + { + return; + } - gAgentCamera.resetView(TRUE, TRUE); - gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + gAgentCamera.resetView(TRUE, TRUE); + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); } class LLViewLookAtLastChatter : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgentCamera.lookAtLastChat(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgentCamera.lookAtLastChat(); + return true; + } }; class LLViewMouselook : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (!gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToMouselook(); - } - else - { - gAgentCamera.changeCameraToDefault(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (!gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToMouselook(); + } + else + { + gAgentCamera.changeCameraToDefault(); + } + return true; + } }; class LLViewDefaultUISize : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setF32("UIScaleFactor", 1.0f); - gSavedSettings.setBOOL("UIAutoScale", FALSE); - gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gSavedSettings.setF32("UIScaleFactor", 1.0f); + gSavedSettings.setBOOL("UIAutoScale", FALSE); + gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); + return true; + } }; class LLViewToggleUI : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - LLNotification::Params params("ConfirmHideUI"); - params.functor.function(boost::bind(&LLViewToggleUI::confirm, this, _1, _2)); - LLSD substitutions; + bool handleEvent(const LLSD& userdata) + { + if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) + { + LLNotification::Params params("ConfirmHideUI"); + params.functor.function(boost::bind(&LLViewToggleUI::confirm, this, _1, _2)); + LLSD substitutions; #if LL_DARWIN - substitutions["SHORTCUT"] = "Cmd+Shift+U"; + substitutions["SHORTCUT"] = "Cmd+Shift+U"; #else - substitutions["SHORTCUT"] = "Ctrl+Shift+U"; + substitutions["SHORTCUT"] = "Ctrl+Shift+U"; #endif - params.substitutions = substitutions; - if (!gSavedSettings.getBOOL("HideUIControls")) - { - // hiding, so show notification - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } - } - return true; - } - - void confirm(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (option == 0) // OK - { - gViewerWindow->setUIVisibility(gSavedSettings.getBOOL("HideUIControls")); - LLPanelStandStopFlying::getInstance()->setVisible(gSavedSettings.getBOOL("HideUIControls")); - gSavedSettings.setBOOL("HideUIControls",!gSavedSettings.getBOOL("HideUIControls")); - } - } -}; + params.substitutions = substitutions; + if (!gSavedSettings.getBOOL("HideUIControls")) + { + // hiding, so show notification + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } + } + return true; + } -void handle_duplicate_in_place(void*) + void confirm(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (option == 0) // OK + { + gViewerWindow->setUIVisibility(gSavedSettings.getBOOL("HideUIControls")); + LLPanelStandStopFlying::getInstance()->setVisible(gSavedSettings.getBOOL("HideUIControls")); + gSavedSettings.setBOOL("HideUIControls",!gSavedSettings.getBOOL("HideUIControls")); + } + } +}; + +void handle_duplicate_in_place(void*) { - LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; + LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; - LLVector3 offset(0.f, 0.f, 0.f); - LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); + LLVector3 offset(0.f, 0.f, 0.f); + LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); } @@ -4606,121 +4606,121 @@ void handle_duplicate_in_place(void*) * No longer able to support viewer side manipulations in this way * void god_force_inv_owner_permissive(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void*) -{ - typedef std::vector > item_array_t; - item_array_t items; - - LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); - LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); - for ( ; inv_it != inv_end; ++inv_it) - { - if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) - { - LLInventoryObject* obj = *inv_it; - LLPointer new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); - LLPermissions perm(new_item->getPermissions()); - perm.setMaskBase(PERM_ALL); - perm.setMaskOwner(PERM_ALL); - new_item->setPermissions(perm); - items.push_back(new_item); - } - } - item_array_t::iterator end = items.end(); - item_array_t::iterator it; - for(it = items.begin(); it != end; ++it) - { - // since we have the inventory item in the callback, it should not - // invalidate iteration through the selection manager. - object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); - } + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void*) +{ + typedef std::vector > item_array_t; + item_array_t items; + + LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); + LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); + for ( ; inv_it != inv_end; ++inv_it) + { + if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) + { + LLInventoryObject* obj = *inv_it; + LLPointer new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); + LLPermissions perm(new_item->getPermissions()); + perm.setMaskBase(PERM_ALL); + perm.setMaskOwner(PERM_ALL); + new_item->setPermissions(perm); + items.push_back(new_item); + } + } + item_array_t::iterator end = items.end(); + item_array_t::iterator it; + for(it = items.begin(); it != end; ++it) + { + // since we have the inventory item in the callback, it should not + // invalidate iteration through the selection manager. + object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); + } } */ void handle_object_owner_permissive(void*) { - // only send this if they're a god. - if(gAgent.isGodlike()) - { - // do the objects. - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); - } + // only send this if they're a god. + if(gAgent.isGodlike()) + { + // do the objects. + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); + } } void handle_object_owner_self(void*) { - // only send this if they're a god. - if(gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); - } + // only send this if they're a god. + if(gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); + } } // Shortcut to set owner permissions to not editable. void handle_object_lock(void*) { - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); } void handle_object_asset_ids(void*) { - // only send this if they're a god. - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); - } + // only send this if they're a god. + if (gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); + } } void handle_force_parcel_owner_to_me(void*) { - LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); + LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); } void handle_force_parcel_to_content(void*) { - LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); + LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); } void handle_claim_public_land(void*) { - if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) - { - LLNotificationsUtil::add("ClaimPublicLand"); - return; - } - - LLVector3d west_south_global; - LLVector3d east_north_global; - LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); - LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); - LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GodlikeMessage"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - msg->nextBlock("MethodData"); - msg->addString("Method", "claimpublicland"); - msg->addUUID("Invoice", LLUUID::null); - std::string buffer; - buffer = llformat( "%f", west_south.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", west_south.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - gAgent.sendReliableMessage(); + if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) + { + LLNotificationsUtil::add("ClaimPublicLand"); + return; + } + + LLVector3d west_south_global; + LLVector3d east_north_global; + LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); + LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); + LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("GodlikeMessage"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + msg->nextBlock("MethodData"); + msg->addString("Method", "claimpublicland"); + msg->addUUID("Invoice", LLUUID::null); + std::string buffer; + buffer = llformat( "%f", west_south.mV[VX]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", west_south.mV[VY]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", east_north.mV[VX]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + buffer = llformat( "%f", east_north.mV[VY]); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + gAgent.sendReliableMessage(); } @@ -4728,286 +4728,286 @@ void handle_claim_public_land(void*) // HACK for easily testing new avatar geometry void handle_god_request_avatar_geometry(void *) { - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); - } + if (gAgent.isGodlike()) + { + LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); + } } static bool get_derezzable_objects( - EDeRezDestination dest, - std::string& error, - LLViewerRegion*& first_region, - std::vector* derez_objectsp, - bool only_check = false) -{ - bool found = false; - - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if (derez_objectsp) - derez_objectsp->reserve(selection->getRootObjectCount()); - - // Check conditions that we can't deal with, building a list of - // everything that we'll actually be derezzing. - for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); - iter != selection->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerRegion* region = object->getRegion(); - if (!first_region) - { - first_region = region; - } - else - { - if(region != first_region) - { - // Derez doesn't work at all if the some of the objects - // are in regions besides the first object selected. - - // ...crosses region boundaries - error = "AcquireErrorObjectSpan"; - break; - } - } - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } - - // If AssetContainers are being sent back, they will appear as - // boxes in the owner's inventory. - if (object->getNVPair("AssetContainer") - && dest != DRD_RETURN_TO_OWNER) - { - // this object is an asset container, derez its contents, not it - LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; - /* - object->requestInventory(container_inventory_arrived, - (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); - */ - continue; - } - BOOL can_derez_current = FALSE; - switch(dest) - { - case DRD_TAKE_INTO_AGENT_INVENTORY: - case DRD_TRASH: - if (!object->isPermanentEnforced() && - ((node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) - || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)))) - { - can_derez_current = TRUE; - } - break; - - case DRD_RETURN_TO_OWNER: - if(!object->isAttachment()) - { - can_derez_current = TRUE; - } - break; - - default: - if((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permCopy()) - || gAgent.isGodlike()) - { - can_derez_current = TRUE; - } - break; - } - if(can_derez_current) - { - found = true; - - if (only_check) - // one found, no need to traverse to the end - break; - - if (derez_objectsp) - derez_objectsp->push_back(object); - - } - } - - return found; + EDeRezDestination dest, + std::string& error, + LLViewerRegion*& first_region, + std::vector* derez_objectsp, + bool only_check = false) +{ + bool found = false; + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + + if (derez_objectsp) + derez_objectsp->reserve(selection->getRootObjectCount()); + + // Check conditions that we can't deal with, building a list of + // everything that we'll actually be derezzing. + for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + iter != selection->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + LLViewerRegion* region = object->getRegion(); + if (!first_region) + { + first_region = region; + } + else + { + if(region != first_region) + { + // Derez doesn't work at all if the some of the objects + // are in regions besides the first object selected. + + // ...crosses region boundaries + error = "AcquireErrorObjectSpan"; + break; + } + } + if (object->isAvatar()) + { + // ...don't acquire avatars + continue; + } + + // If AssetContainers are being sent back, they will appear as + // boxes in the owner's inventory. + if (object->getNVPair("AssetContainer") + && dest != DRD_RETURN_TO_OWNER) + { + // this object is an asset container, derez its contents, not it + LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; + /* + object->requestInventory(container_inventory_arrived, + (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); + */ + continue; + } + BOOL can_derez_current = FALSE; + switch(dest) + { + case DRD_TAKE_INTO_AGENT_INVENTORY: + case DRD_TRASH: + if (!object->isPermanentEnforced() && + ((node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) + || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)))) + { + can_derez_current = TRUE; + } + break; + + case DRD_RETURN_TO_OWNER: + if(!object->isAttachment()) + { + can_derez_current = TRUE; + } + break; + + default: + if((node->mPermissions->allowTransferTo(gAgent.getID()) + && object->permCopy()) + || gAgent.isGodlike()) + { + can_derez_current = TRUE; + } + break; + } + if(can_derez_current) + { + found = true; + + if (only_check) + // one found, no need to traverse to the end + break; + + if (derez_objectsp) + derez_objectsp->push_back(object); + + } + } + + return found; } static bool can_derez(EDeRezDestination dest) { - LLViewerRegion* first_region = NULL; - std::string error; - return get_derezzable_objects(dest, error, first_region, NULL, true); + LLViewerRegion* first_region = NULL; + std::string error; + return get_derezzable_objects(dest, error, first_region, NULL, true); } static void derez_objects( - EDeRezDestination dest, - const LLUUID& dest_id, - LLViewerRegion*& first_region, - std::string& error, - std::vector* objectsp) -{ - std::vector derez_objects; - - if (!objectsp) // if objects to derez not specified - { - // get them from selection - if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) - { - LL_WARNS() << "No objects to derez" << LL_ENDL; - return; - } - - objectsp = &derez_objects; - } - - - if(gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - - // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per - // root. I lopped off a few (33) to provide a bit - // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. - // This gives us a maximum of 63500 root objects - which should - // satisfy anybody. - const S32 MAX_ROOTS_PER_PACKET = 250; - const S32 MAX_PACKET_COUNT = 254; - F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); - if(packets > (F32)MAX_PACKET_COUNT) - { - error = "AcquireErrorTooManyObjects"; - } - - if(error.empty() && objectsp->size() > 0) - { - U8 d = (U8)dest; - LLUUID tid; - tid.generate(); - U8 packet_count = (U8)packets; - S32 object_index = 0; - S32 objects_in_packet = 0; - LLMessageSystem* msg = gMessageSystem; - for(U8 packet_number = 0; - packet_number < packet_count; - ++packet_number) - { - msg->newMessageFast(_PREHASH_DeRezObject); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_AgentBlock); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->addU8Fast(_PREHASH_Destination, d); - msg->addUUIDFast(_PREHASH_DestinationID, dest_id); - msg->addUUIDFast(_PREHASH_TransactionID, tid); - msg->addU8Fast(_PREHASH_PacketCount, packet_count); - msg->addU8Fast(_PREHASH_PacketNumber, packet_number); - objects_in_packet = 0; - while((object_index < objectsp->size()) - && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) - - { - LLViewerObject* object = objectsp->at(object_index++); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - // VEFFECT: DerezObject - LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(object->getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - } - msg->sendReliable(first_region->getHost()); - } - make_ui_sound("UISndObjectRezOut"); - - // Busy count decremented by inventory update, so only increment - // if will be causing an update. - if (dest != DRD_RETURN_TO_OWNER) - { - gViewerWindow->getWindow()->incBusyCount(); - } - } - else if(!error.empty()) - { - LLNotificationsUtil::add(error); - } + EDeRezDestination dest, + const LLUUID& dest_id, + LLViewerRegion*& first_region, + std::string& error, + std::vector* objectsp) +{ + std::vector derez_objects; + + if (!objectsp) // if objects to derez not specified + { + // get them from selection + if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) + { + LL_WARNS() << "No objects to derez" << LL_ENDL; + return; + } + + objectsp = &derez_objects; + } + + + if(gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + + // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per + // root. I lopped off a few (33) to provide a bit + // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. + // This gives us a maximum of 63500 root objects - which should + // satisfy anybody. + const S32 MAX_ROOTS_PER_PACKET = 250; + const S32 MAX_PACKET_COUNT = 254; + F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); + if(packets > (F32)MAX_PACKET_COUNT) + { + error = "AcquireErrorTooManyObjects"; + } + + if(error.empty() && objectsp->size() > 0) + { + U8 d = (U8)dest; + LLUUID tid; + tid.generate(); + U8 packet_count = (U8)packets; + S32 object_index = 0; + S32 objects_in_packet = 0; + LLMessageSystem* msg = gMessageSystem; + for(U8 packet_number = 0; + packet_number < packet_count; + ++packet_number) + { + msg->newMessageFast(_PREHASH_DeRezObject); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_AgentBlock); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->addU8Fast(_PREHASH_Destination, d); + msg->addUUIDFast(_PREHASH_DestinationID, dest_id); + msg->addUUIDFast(_PREHASH_TransactionID, tid); + msg->addU8Fast(_PREHASH_PacketCount, packet_count); + msg->addU8Fast(_PREHASH_PacketNumber, packet_number); + objects_in_packet = 0; + while((object_index < objectsp->size()) + && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) + + { + LLViewerObject* object = objectsp->at(object_index++); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); + // VEFFECT: DerezObject + LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(object->getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + } + msg->sendReliable(first_region->getHost()); + } + make_ui_sound("UISndObjectRezOut"); + + // Busy count decremented by inventory update, so only increment + // if will be causing an update. + if (dest != DRD_RETURN_TO_OWNER) + { + gViewerWindow->getWindow()->incBusyCount(); + } + } + else if(!error.empty()) + { + LLNotificationsUtil::add(error); + } } static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) { - LLViewerRegion* first_region = NULL; - std::string error; - derez_objects(dest, dest_id, first_region, error, NULL); + LLViewerRegion* first_region = NULL; + std::string error; + derez_objects(dest, dest_id, first_region, error, NULL); } void handle_take_copy() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } void handle_link_objects() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - LLFloaterReg::toggleInstanceOrBringToFront("places"); - } - else - { - LLSelectMgr::getInstance()->linkObjects(); - } + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLFloaterReg::toggleInstanceOrBringToFront("places"); + } + else + { + LLSelectMgr::getInstance()->linkObjects(); + } } // You can return an object to its owner if it is on your land. class LLObjectReturn : public view_listener_t { public: - LLObjectReturn() : mFirstRegion(NULL) {} + LLObjectReturn() : mFirstRegion(NULL) {} private: - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; - - mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; + + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. - get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); - return true; - } + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); + return true; + } - bool onReturnToOwner(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects); - } + bool onReturnToOwner(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects); + } - mReturnableObjects.clear(); - mError.clear(); - mFirstRegion = NULL; + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; - // drop reference to current selection - mObjectSelection = NULL; - return false; - } + // drop reference to current selection + mObjectSelection = NULL; + return false; + } - LLObjectSelectionHandle mObjectSelection; + LLObjectSelectionHandle mObjectSelection; - std::vector mReturnableObjects; - std::string mError; - LLViewerRegion* mFirstRegion; + std::vector mReturnableObjects; + std::string mError; + LLViewerRegion* mFirstRegion; }; @@ -5015,187 +5015,187 @@ private: // over land you own. class LLObjectEnableReturn : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - // Do not enable if nothing selected - return false; - } + bool handleEvent(const LLSD& userdata) + { + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + // Do not enable if nothing selected + return false; + } #ifdef HACKED_GODLIKE_VIEWER - bool new_value = true; + bool new_value = true; #else - bool new_value = false; - if (gAgent.isGodlike()) - { - new_value = true; - } - else - { - new_value = can_derez(DRD_RETURN_TO_OWNER); - } + bool new_value = false; + if (gAgent.isGodlike()) + { + new_value = true; + } + else + { + new_value = can_derez(DRD_RETURN_TO_OWNER); + } #endif - return new_value; - } + return new_value; + } }; void force_take_copy(void*) { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); } void handle_take() { - // we want to use the folder this was derezzed from if it's - // available. Otherwise, derez to the normal place. - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - BOOL you_own_everything = TRUE; - BOOL locked_but_takeable_object = FALSE; - LLUUID category_id; - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if(object) - { - if(!object->permYouOwner()) - { - you_own_everything = FALSE; - } - - if(!object->permMove()) - { - locked_but_takeable_object = TRUE; - } - } - if(node->mFolderID.notNull()) - { - if(category_id.isNull()) - { - category_id = node->mFolderID; - } - else if(category_id != node->mFolderID) - { - // we have found two potential destinations. break out - // now and send to the default location. - category_id.setNull(); - break; - } - } - } - if(category_id.notNull()) - { - // there is an unambiguous destination. See if this agent has - // such a location and it is not in the trash or library - if(!gInventory.getCategory(category_id)) - { - // nope, set to NULL. - category_id.setNull(); - } - if(category_id.notNull()) - { - // check trash - const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) - { - category_id.setNull(); - } - - // check library - if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) - { - category_id.setNull(); - } - - // check inbox - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); - if (category_id == inbox_id || gInventory.isObjectDescendentOf(category_id, inbox_id)) - { - category_id.setNull(); - } - } - } - if(category_id.isNull()) - { - category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - } - LLSD payload; - payload["folder_id"] = category_id; - - LLNotification::Params params("ConfirmObjectTakeLock"); - params.payload(payload); - // MAINT-290 - // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. - // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened - params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); - - if(locked_but_takeable_object || - !you_own_everything) - { - if(locked_but_takeable_object && you_own_everything) - { - params.name("ConfirmObjectTakeLock"); - } - else if(!locked_but_takeable_object && !you_own_everything) - { - params.name("ConfirmObjectTakeNoOwn"); - } - else - { - params.name("ConfirmObjectTakeLockNoOwn"); - } - - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } + // we want to use the folder this was derezzed from if it's + // available. Otherwise, derez to the normal place. + if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + return; + } + + BOOL you_own_everything = TRUE; + BOOL locked_but_takeable_object = FALSE; + LLUUID category_id; + + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if(object) + { + if(!object->permYouOwner()) + { + you_own_everything = FALSE; + } + + if(!object->permMove()) + { + locked_but_takeable_object = TRUE; + } + } + if(node->mFolderID.notNull()) + { + if(category_id.isNull()) + { + category_id = node->mFolderID; + } + else if(category_id != node->mFolderID) + { + // we have found two potential destinations. break out + // now and send to the default location. + category_id.setNull(); + break; + } + } + } + if(category_id.notNull()) + { + // there is an unambiguous destination. See if this agent has + // such a location and it is not in the trash or library + if(!gInventory.getCategory(category_id)) + { + // nope, set to NULL. + category_id.setNull(); + } + if(category_id.notNull()) + { + // check trash + const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) + { + category_id.setNull(); + } + + // check library + if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) + { + category_id.setNull(); + } + + // check inbox + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); + if (category_id == inbox_id || gInventory.isObjectDescendentOf(category_id, inbox_id)) + { + category_id.setNull(); + } + } + } + if(category_id.isNull()) + { + category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + } + LLSD payload; + payload["folder_id"] = category_id; + + LLNotification::Params params("ConfirmObjectTakeLock"); + params.payload(payload); + // MAINT-290 + // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. + // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened + params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); + + if(locked_but_takeable_object || + !you_own_everything) + { + if(locked_but_takeable_object && you_own_everything) + { + params.name("ConfirmObjectTakeLock"); + } + else if(!locked_but_takeable_object && !you_own_everything) + { + params.name("ConfirmObjectTakeNoOwn"); + } + else + { + params.name("ConfirmObjectTakeLockNoOwn"); + } + + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } } void handle_object_show_inspector() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* objectp = selection->getFirstRootObject(TRUE); - if (!objectp) - { - return; - } + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* objectp = selection->getFirstRootObject(TRUE); + if (!objectp) + { + return; + } - LLSD params; - params["object_id"] = objectp->getID(); - LLFloaterReg::showInstance("inspect_object", params); + LLSD params; + params["object_id"] = objectp->getID(); + LLFloaterReg::showInstance("inspect_object", params); } void handle_avatar_show_inspector() { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLSD params; - params["avatar_id"] = avatar->getID(); - LLFloaterReg::showInstance("inspect_avatar", params); - } + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLSD params; + params["avatar_id"] = avatar->getID(); + LLFloaterReg::showInstance("inspect_avatar", params); + } } bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection_handle) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(enable_take() && (option == 0)) - { - derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(enable_take() && (option == 0)) + { + derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); + } + return false; } // You can take an item when it is public and transferrable, or when @@ -5203,101 +5203,101 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect // one item selected can be copied to inventory. BOOL enable_take() { - if (sitting_on_selection()) - { - return FALSE; - } - - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } + if (sitting_on_selection()) + { + return FALSE; + } + + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (object->isAvatar()) + { + // ...don't acquire avatars + continue; + } #ifdef HACKED_GODLIKE_VIEWER - return TRUE; + return TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() + if (!LLGridManager::getInstance()->isInProductionGrid() && gAgent.isGodlike()) - { - return TRUE; - } + { + return TRUE; + } # endif - if(!object->isPermanentEnforced() && - ((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permModify()) - || (node->mPermissions->getOwner() == gAgent.getID()))) - { - return !object->isAttachment(); - } + if(!object->isPermanentEnforced() && + ((node->mPermissions->allowTransferTo(gAgent.getID()) + && object->permModify()) + || (node->mPermissions->getOwner() == gAgent.getID()))) + { + return !object->isAttachment(); + } #endif - } - return FALSE; + } + return FALSE; } void handle_buy_or_take() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - if (is_selection_buy_not_take()) - { - S32 total_price = selection_price(); - - if (total_price <= gStatusBar->getBalance() || total_price == 0) - { - handle_buy(); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", total_price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); - } - } - else - { - handle_take(); - } + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + return; + } + + if (is_selection_buy_not_take()) + { + S32 total_price = selection_price(); + + if (total_price <= gStatusBar->getBalance() || total_price == 0) + { + handle_buy(); + } + else + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", total_price); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "this_object_costs", args ), total_price ); + } + } + else + { + handle_take(); + } } bool visible_buy_object() { - return is_selection_buy_not_take() && enable_buy_object(); + return is_selection_buy_not_take() && enable_buy_object(); } bool visible_take_object() { - return !is_selection_buy_not_take() && enable_take(); + return !is_selection_buy_not_take() && enable_take(); } bool tools_visible_buy_object() { - return is_selection_buy_not_take(); + return is_selection_buy_not_take(); } bool tools_visible_take_object() { - return !is_selection_buy_not_take(); + return !is_selection_buy_not_take(); } class LLToolsEnableBuyOrTake : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool is_buy = is_selection_buy_not_take(); - bool new_value = is_buy ? enable_buy_object() : enable_take(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool is_buy = is_selection_buy_not_take(); + bool new_value = is_buy ? enable_buy_object() : enable_take(); + return new_value; + } }; // This is a small helper function to determine if we have a buy or a @@ -5318,255 +5318,255 @@ class LLToolsEnableBuyOrTake : public view_listener_t // FALSE if selection is a 'take' BOOL is_selection_buy_not_take() { - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale, thus, - // it's a buy - return TRUE; - } - } - return FALSE; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) + { + // you do not own the object and it is for sale, thus, + // it's a buy + return TRUE; + } + } + return FALSE; } S32 selection_price() { - S32 total_price = 0; - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale. - // Add its price. - total_price += node->mSaleInfo.getSalePrice(); - } - } - - return total_price; + S32 total_price = 0; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) + { + // you do not own the object and it is for sale. + // Add its price. + total_price += node->mSaleInfo.getSalePrice(); + } + } + + return total_price; } /* bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LL_INFOS() << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << LL_ENDL; - LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_INFOS() << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << LL_ENDL; + LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); + } + return false; } */ void show_buy_currency(const char* extra) { - // Don't show currency web page for branded clients. + // Don't show currency web page for branded clients. /* - std::ostringstream mesg; - if (extra != NULL) - { - mesg << extra << "\n \n"; - } - mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; + std::ostringstream mesg; + if (extra != NULL) + { + mesg << extra << "\n \n"; + } + mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; */ - LLSD args; - if (extra != NULL) - { - args["EXTRA"] = extra; - } - LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); + LLSD args; + if (extra != NULL) + { + args["EXTRA"] = extra; + } + LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); } void handle_buy() { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - LLSaleInfo sale_info; - BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); - if (!valid) return; + LLSaleInfo sale_info; + BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); + if (!valid) return; - S32 price = sale_info.getSalePrice(); - - if (price > 0 && price > gStatusBar->getBalance()) - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); - return; - } + S32 price = sale_info.getSalePrice(); - if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) - { - handle_buy_contents(sale_info); - } - else - { - handle_buy_object(sale_info); - } + if (price > 0 && price > gStatusBar->getBalance()) + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", price); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); + return; + } + + if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) + { + handle_buy_contents(sale_info); + } + else + { + handle_buy_object(sale_info); + } } bool anyone_copy_selection(LLSelectNode* nodep) { - bool perm_copy = (bool)(nodep->getObject()->permCopy()); - bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); - return perm_copy && all_copy; + bool perm_copy = (bool)(nodep->getObject()->permCopy()); + bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); + return perm_copy && all_copy; } bool for_sale_selection(LLSelectNode* nodep) { - return nodep->mSaleInfo.isForSale() - && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER - && (nodep->mPermissions->getMaskOwner() & PERM_COPY - || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); + return nodep->mSaleInfo.isForSale() + && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER + && (nodep->mPermissions->getMaskOwner() & PERM_COPY + || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); } BOOL sitting_on_selection() { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (!node) - { - return FALSE; - } + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (!node) + { + return FALSE; + } - if (!node->mValid) - { - return FALSE; - } + if (!node->mValid) + { + return FALSE; + } - LLViewerObject* root_object = node->getObject(); - if (!root_object) - { - return FALSE; - } + LLViewerObject* root_object = node->getObject(); + if (!root_object) + { + return FALSE; + } - // Need to determine if avatar is sitting on this object - if (!isAgentAvatarValid()) return FALSE; + // Need to determine if avatar is sitting on this object + if (!isAgentAvatarValid()) return FALSE; - return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); + return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); } class LLToolsSaveToObjectInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if(node && (node->mValid) && (!node->mFromTaskID.isNull())) + { + // *TODO: check to see if the fromtaskid object exists. + derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); + } + return true; + } }; class LLToolsEnablePathfinding : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); - } + bool handleEvent(const LLSD& userdata) + { + return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + } }; class LLToolsEnablePathfindingView : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); + } }; class LLToolsDoPathfindingRebakeRegion : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); - - if (hasPathfinding) - { - LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); - } + bool handleEvent(const LLSD& userdata) + { + bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); + + if (hasPathfinding) + { + LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); + } - return hasPathfinding; - } + return hasPathfinding; + } }; class LLToolsEnablePathfindingRebakeRegion : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool returnValue = false; + bool handleEvent(const LLSD& userdata) + { + bool returnValue = false; if (LLNavigationBar::instanceExists()) { returnValue = LLNavigationBar::getInstance()->isRebakeNavMeshAvailable(); } - return returnValue; - } + return returnValue; + } }; // Round the position of all root objects to the grid class LLToolsSnapObjectXY : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if (obj->permModify()) - { - LLVector3d pos_global = obj->getPositionGlobal(); - F64 round_x = fmod(pos_global.mdV[VX], snap_size); - if (round_x < snap_size * 0.5) - { - // closer to round down - pos_global.mdV[VX] -= round_x; - } - else - { - // closer to round up - pos_global.mdV[VX] -= round_x; - pos_global.mdV[VX] += snap_size; - } - - F64 round_y = fmod(pos_global.mdV[VY], snap_size); - if (round_y < snap_size * 0.5) - { - pos_global.mdV[VY] -= round_y; - } - else - { - pos_global.mdV[VY] -= round_y; - pos_global.mdV[VY] += snap_size; - } - - obj->setPositionGlobal(pos_global, FALSE); - } - } - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); - return true; - } + bool handleEvent(const LLSD& userdata) + { + F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); + + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (obj->permModify()) + { + LLVector3d pos_global = obj->getPositionGlobal(); + F64 round_x = fmod(pos_global.mdV[VX], snap_size); + if (round_x < snap_size * 0.5) + { + // closer to round down + pos_global.mdV[VX] -= round_x; + } + else + { + // closer to round up + pos_global.mdV[VX] -= round_x; + pos_global.mdV[VX] += snap_size; + } + + F64 round_y = fmod(pos_global.mdV[VY], snap_size); + if (round_y < snap_size * 0.5) + { + pos_global.mdV[VY] -= round_y; + } + else + { + pos_global.mdV[VY] -= round_y; + pos_global.mdV[VY] += snap_size; + } + + obj->setPositionGlobal(pos_global, FALSE); + } + } + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + return true; + } }; // Determine if the option to cycle between linked prims is shown class LLToolsEnableSelectNextPart : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { bool new_value = (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && (gSavedSettings.getBOOL("EditLinkedParts") || LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool())); - return new_value; - } + return new_value; + } }; // Cycle selection through linked children or/and faces in selected object. @@ -5641,61 +5641,61 @@ class LLToolsSelectNextPartFace : public view_listener_t } } - S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - if (cycle_linked && object_count && restart_face_on_part) - { - LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if (selected && selected->getRootEdit()) - { - LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); - children.push_front(selected->getRootEdit()); // need root in the list too - - for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) - { - if ((*iter)->isSelected()) - { - if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include - { - to_select = *iter; - if (fwd) - { - // stop searching if going forward; repeat to get last hit if backward - break; - } - } - else if ((object_count == 1) || (ifwd || iprev)) // single selection or include - { - if (fwd || ifwd) - { - ++iter; - while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) - { - ++iter; // skip sitting avatars and selected if include - } - } - else // backward - { - iter = (iter == children.begin() ? children.end() : iter); - --iter; - while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) - { - --iter; // skip sitting avatars and selected if include - } - } - iter = (iter == children.end() ? children.begin() : iter); - to_select = *iter; - break; - } - } - } - } - } + S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (cycle_linked && object_count && restart_face_on_part) + { + LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (selected && selected->getRootEdit()) + { + LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); + children.push_front(selected->getRootEdit()); // need root in the list too + + for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) + { + if ((*iter)->isSelected()) + { + if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include + { + to_select = *iter; + if (fwd) + { + // stop searching if going forward; repeat to get last hit if backward + break; + } + } + else if ((object_count == 1) || (ifwd || iprev)) // single selection or include + { + if (fwd || ifwd) + { + ++iter; + while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) + { + ++iter; // skip sitting avatars and selected if include + } + } + else // backward + { + iter = (iter == children.begin() ? children.end() : iter); + --iter; + while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) + { + --iter; // skip sitting avatars and selected if include + } + } + iter = (iter == children.end() ? children.begin() : iter); + to_select = *iter; + break; + } + } + } + } + } if (to_select) { if (gFocusMgr.childHasKeyboardFocus(gFloaterTools)) { - gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes + gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes } if (fwd || prev) { @@ -5723,455 +5723,455 @@ class LLToolsSelectNextPartFace : public view_listener_t } return true; } - return true; - } + return true; + } }; class LLToolsStopAllAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.stopCurrentAnimations(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.stopCurrentAnimations(); + return true; + } }; class LLToolsReleaseKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.forceReleaseControls(); + bool handleEvent(const LLSD& userdata) + { + gAgent.forceReleaseControls(); - return true; - } + return true; + } }; class LLToolsEnableReleaseKeys : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gAgent.anyControlGrabbed(); - } + bool handleEvent(const LLSD& userdata) + { + return gAgent.anyControlGrabbed(); + } }; class LLEditEnableCut : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); + return new_value; + } }; class LLEditCut : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->cut(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->cut(); + } + return true; + } }; class LLEditEnableCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); + return new_value; + } }; class LLEditCopy : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->copy(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->copy(); + } + return true; + } }; class LLEditEnablePaste : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); + return new_value; + } }; class LLEditPaste : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->paste(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->paste(); + } + return true; + } }; class LLEditEnableDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); + return new_value; + } }; class LLEditDelete : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // If a text field can do a deletion, it gets precedence over deleting - // an object in the world. - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) - { - LLEditMenuHandler::gEditMenuHandler->doDelete(); - } + bool handleEvent(const LLSD& userdata) + { + // If a text field can do a deletion, it gets precedence over deleting + // an object in the world. + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) + { + LLEditMenuHandler::gEditMenuHandler->doDelete(); + } - // and close any pie/context menus when done - gMenuHolder->hideMenus(); + // and close any pie/context menus when done + gMenuHolder->hideMenus(); - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return true; - } + // When deleting an object we may not actually be done + // Keep selection so we know what to delete when confirmation is needed about the delete + gMenuObject->hide(); + return true; + } }; void handle_spellcheck_replace_with_suggestion(const LLUICtrl* ctrl, const LLSD& param) { - const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; - if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) - { - return; - } + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return; + } - U32 index = 0; - if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) - { - return; - } + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return; + } - spellcheck_handler->replaceWithSuggestion(index); + spellcheck_handler->replaceWithSuggestion(index); } bool visible_spellcheck_suggestion(LLUICtrl* ctrl, const LLSD& param) { - LLMenuItemGL* item = dynamic_cast(ctrl); - const LLContextMenu* menu = (item) ? dynamic_cast(item->getParent()) : NULL; - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; - if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) - { - return false; - } + LLMenuItemGL* item = dynamic_cast(ctrl); + const LLContextMenu* menu = (item) ? dynamic_cast(item->getParent()) : NULL; + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return false; + } - U32 index = 0; - if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) - { - return false; - } + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return false; + } - item->setLabel(spellcheck_handler->getSuggestion(index)); - return true; + item->setLabel(spellcheck_handler->getSuggestion(index)); + return true; } void handle_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; - if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) - { - spellcheck_handler->addToDictionary(); - } + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) + { + spellcheck_handler->addToDictionary(); + } } bool enable_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; - return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); } void handle_spellcheck_add_to_ignore(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); - LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; - if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) - { - spellcheck_handler->addToIgnore(); - } + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) + { + spellcheck_handler->addToIgnore(); + } } bool enable_spellcheck_add_to_ignore(const LLUICtrl* ctrl) { - const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); - const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; - return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); } bool enable_object_return() { - return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && - (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); + return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && + (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); } bool enable_object_delete() { - bool new_value = + bool new_value = #ifdef HACKED_GODLIKE_VIEWER - TRUE; + TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - (!LLGridManager::getInstance()->isInProductionGrid() + (!LLGridManager::getInstance()->isInProductionGrid() && gAgent.isGodlike()) || # endif - LLSelectMgr::getInstance()->canDoDelete(); + LLSelectMgr::getInstance()->canDoDelete(); #endif - return new_value; + return new_value; } class LLObjectsReturnPackage { public: - LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; - ~LLObjectsReturnPackage() - { - mObjectSelection.clear(); - mReturnableObjects.clear(); - mError.clear(); - mFirstRegion = NULL; - }; + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + ~LLObjectsReturnPackage() + { + mObjectSelection.clear(); + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; + }; - LLObjectSelectionHandle mObjectSelection; - std::vector mReturnableObjects; - std::string mError; - LLViewerRegion *mFirstRegion; + LLObjectSelectionHandle mObjectSelection; + std::vector mReturnableObjects; + std::string mError; + LLViewerRegion *mFirstRegion; }; static void return_objects(LLObjectsReturnPackage *objectsReturnPackage, const LLSD& notification, const LLSD& response) { - if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); - } + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); + } - delete objectsReturnPackage; + delete objectsReturnPackage; } void handle_object_return() { - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); - objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); + objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. - get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); - } + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); + } } void handle_object_delete() { - if (LLSelectMgr::getInstance()) - { - LLSelectMgr::getInstance()->doDelete(); - } + if (LLSelectMgr::getInstance()) + { + LLSelectMgr::getInstance()->doDelete(); + } - // and close any pie/context menus when done - gMenuHolder->hideMenus(); + // and close any pie/context menus when done + gMenuHolder->hideMenus(); - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return; + // When deleting an object we may not actually be done + // Keep selection so we know what to delete when confirmation is needed about the delete + gMenuObject->hide(); + return; } void handle_force_delete(void*) { - LLSelectMgr::getInstance()->selectForceDelete(); + LLSelectMgr::getInstance()->selectForceDelete(); } class LLViewEnableJoystickFlycam : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); + return new_value; + } }; class LLViewEnableLastChatter : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // *TODO: add check that last chatter is in range - bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // *TODO: add check that last chatter is in range + bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); + return new_value; + } }; class LLEditEnableDeselect : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); + return new_value; + } }; class LLEditDeselect : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->deselect(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->deselect(); + } + return true; + } }; class LLEditEnableSelectAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); + return new_value; + } }; class LLEditSelectAll : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->selectAll(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler ) + { + LLEditMenuHandler::gEditMenuHandler->selectAll(); + } + return true; + } }; class LLEditEnableUndo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); + return new_value; + } }; class LLEditUndo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) - { - LLEditMenuHandler::gEditMenuHandler->undo(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) + { + LLEditMenuHandler::gEditMenuHandler->undo(); + } + return true; + } }; class LLEditEnableRedo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); + return new_value; + } }; class LLEditRedo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) - { - LLEditMenuHandler::gEditMenuHandler->redo(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) + { + LLEditMenuHandler::gEditMenuHandler->redo(); + } + return true; + } }; void print_object_info(void*) { - LLSelectMgr::getInstance()->selectionDump(); + LLSelectMgr::getInstance()->selectionDump(); } void print_agent_nvpairs(void*) { - LLViewerObject *objectp; + LLViewerObject *objectp; - LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; + LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; - objectp = gObjectList.findObject(gAgentID); - if (objectp) - { - objectp->printNameValuePairs(); - } - else - { - LL_INFOS() << "Can't find agent object" << LL_ENDL; - } + objectp = gObjectList.findObject(gAgentID); + if (objectp) + { + objectp->printNameValuePairs(); + } + else + { + LL_INFOS() << "Can't find agent object" << LL_ENDL; + } - LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; + LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; } void show_debug_menus() { - // this might get called at login screen where there is no menu so only toggle it if one exists - if ( gMenuBarView ) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - BOOL qamode = gSavedSettings.getBOOL("QAMode"); - - gMenuBarView->setItemVisible("Advanced", debug); -// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden - - gMenuBarView->setItemVisible("Debug", qamode); - gMenuBarView->setItemEnabled("Debug", qamode); - - gMenuBarView->setItemVisible("Develop", qamode); - gMenuBarView->setItemEnabled("Develop", qamode); - - // Server ('Admin') menu hidden when not in godmode. - const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); - gMenuBarView->setItemVisible("Admin", show_server_menu); - gMenuBarView->setItemEnabled("Admin", show_server_menu); - } - if (gLoginMenuBarView) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - gLoginMenuBarView->setItemVisible("Debug", debug); - gLoginMenuBarView->setItemEnabled("Debug", debug); - } + // this might get called at login screen where there is no menu so only toggle it if one exists + if ( gMenuBarView ) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + BOOL qamode = gSavedSettings.getBOOL("QAMode"); + + gMenuBarView->setItemVisible("Advanced", debug); +// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + + gMenuBarView->setItemVisible("Debug", qamode); + gMenuBarView->setItemEnabled("Debug", qamode); + + gMenuBarView->setItemVisible("Develop", qamode); + gMenuBarView->setItemEnabled("Develop", qamode); + + // Server ('Admin') menu hidden when not in godmode. + const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); + gMenuBarView->setItemVisible("Admin", show_server_menu); + gMenuBarView->setItemEnabled("Admin", show_server_menu); + } + if (gLoginMenuBarView) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + gLoginMenuBarView->setItemVisible("Debug", debug); + gLoginMenuBarView->setItemEnabled("Debug", debug); + } } void toggle_debug_menus(void*) { - BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); - gSavedSettings.setBOOL("UseDebugMenus", visible); - show_debug_menus(); + BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); + gSavedSettings.setBOOL("UseDebugMenus", visible); + show_debug_menus(); } @@ -6182,292 +6182,292 @@ void toggle_debug_menus(void*) // void handle_export_selected( void * ) // { -// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); -// if (selection->isEmpty()) -// { -// return; -// } -// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; - -// gExporterRequestID.generate(); -// gExportDirectory = ""; - -// LLMessageSystem* msg = gMessageSystem; -// msg->newMessageFast(_PREHASH_ObjectExportSelected); -// msg->nextBlockFast(_PREHASH_AgentData); -// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); -// msg->addS16Fast(_PREHASH_VolumeDetail, 4); - -// for (LLObjectSelection::root_iterator iter = selection->root_begin(); -// iter != selection->root_end(); iter++) -// { -// LLSelectNode* node = *iter; -// LLViewerObject* object = node->getObject(); -// msg->nextBlockFast(_PREHASH_ObjectData); -// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); -// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; -// } -// msg->sendReliable(gAgent.getRegion()->getHost()); - -// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); +// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); +// if (selection->isEmpty()) +// { +// return; +// } +// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; + +// gExporterRequestID.generate(); +// gExportDirectory = ""; + +// LLMessageSystem* msg = gMessageSystem; +// msg->newMessageFast(_PREHASH_ObjectExportSelected); +// msg->nextBlockFast(_PREHASH_AgentData); +// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); +// msg->addS16Fast(_PREHASH_VolumeDetail, 4); + +// for (LLObjectSelection::root_iterator iter = selection->root_begin(); +// iter != selection->root_end(); iter++) +// { +// LLSelectNode* node = *iter; +// LLViewerObject* object = node->getObject(); +// msg->nextBlockFast(_PREHASH_ObjectData); +// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); +// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; +// } +// msg->sendReliable(gAgent.getRegion()->getHost()); + +// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); // } // class LLCommunicateNearbyChat : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); + bool handleEvent(const LLSD& userdata) + { + LLFloaterIMContainer* im_box = LLFloaterIMContainer::getInstance(); LLFloaterIMNearbyChat* floater_nearby = LLFloaterReg::getTypedInstance("nearby_chat"); - if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() + if (floater_nearby->isInVisibleChain() && !floater_nearby->isTornOff() && im_box->getSelectedSession() == LLUUID() && im_box->getConversationListItemSize() > 1) - { - im_box->selectNextorPreviousConversation(false); - } - else - { - LLFloaterReg::toggleInstanceOrBringToFront("nearby_chat"); - } - return true; - } + { + im_box->selectNextorPreviousConversation(false); + } + else + { + LLFloaterReg::toggleInstanceOrBringToFront("nearby_chat"); + } + return true; + } }; class LLWorldSetHomeLocation : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // we just send the message and let the server check for failure cases - // server will echo back a "Home position set." alert if it succeeds - // and the home location screencapture happens when that alert is recieved - gAgent.setStartPosition(START_LOCATION_ID_HOME); - return true; - } + bool handleEvent(const LLSD& userdata) + { + // we just send the message and let the server check for failure cases + // server will echo back a "Home position set." alert if it succeeds + // and the home location screencapture happens when that alert is recieved + gAgent.setStartPosition(START_LOCATION_ID_HOME); + return true; + } }; class LLWorldLindenHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); - LLWeb::loadURL(url); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string url = LLFloaterLandHoldings::sHasLindenHome ? LLTrans::getString("lindenhomes_my_home_url") : LLTrans::getString("lindenhomes_get_home_url"); + LLWeb::loadURL(url); + return true; + } }; class LLWorldTeleportHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.teleportHome(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gAgent.teleportHome(); + return true; + } }; class LLWorldAlwaysRun : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // as well as altering the default walk-vs-run state, - // we also change the *current* walk-vs-run state. - if (gAgent.getAlwaysRun()) - { - gAgent.clearAlwaysRun(); - gAgent.clearRunning(); - } - else - { - gAgent.setAlwaysRun(); - gAgent.setRunning(); - } + bool handleEvent(const LLSD& userdata) + { + // as well as altering the default walk-vs-run state, + // we also change the *current* walk-vs-run state. + if (gAgent.getAlwaysRun()) + { + gAgent.clearAlwaysRun(); + gAgent.clearRunning(); + } + else + { + gAgent.setAlwaysRun(); + gAgent.setRunning(); + } - // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); + // tell the simulator. + gAgent.sendWalkRun(gAgent.getAlwaysRun()); - // Update Movement Controls according to AlwaysRun mode - LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); + // Update Movement Controls according to AlwaysRun mode + LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); - return true; - } + return true; + } }; class LLWorldCheckAlwaysRun : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.getAlwaysRun(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgent.getAlwaysRun(); + return new_value; + } }; class LLWorldSetAway : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.getAFK()) - { - gAgent.clearAFK(); - } - else - { - gAgent.setAFK(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.getAFK()) + { + gAgent.clearAFK(); + } + else + { + gAgent.setAFK(); + } + return true; + } }; class LLWorldSetDoNotDisturb : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isDoNotDisturb()) - { - gAgent.setDoNotDisturb(false); - } - else - { - gAgent.setDoNotDisturb(true); - LLNotificationsUtil::add("DoNotDisturbModeSet"); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgent.isDoNotDisturb()) + { + gAgent.setDoNotDisturb(false); + } + else + { + gAgent.setDoNotDisturb(true); + LLNotificationsUtil::add("DoNotDisturbModeSet"); + } + return true; + } }; class LLWorldCreateLandmark : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("add_landmark"); + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("add_landmark"); - return true; - } + return true; + } }; class LLWorldPlaceProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); + bool handleEvent(const LLSD& userdata) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); - return true; - } + return true; + } }; void handle_look_at_selection(const LLSD& param) { - const F32 PADDING_FACTOR = 1.75f; - BOOL zoom = (param.asString() == "zoom"); - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - - LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); - obj_to_cam.normVec(); - - LLUUID object_id; - if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; - } - if (zoom) - { - // Make sure we are not increasing the distance between the camera and object - LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); - distance = llmin(distance, (F32) orig_distance.length()); - - gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), - LLSelectMgr::getInstance()->getSelectionCenterGlobal(), - object_id ); - - } - else - { - gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); - } - } + const F32 PADDING_FACTOR = 1.75f; + BOOL zoom = (param.asString() == "zoom"); + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + + LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); + F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); + + LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); + obj_to_cam.normVec(); + + LLUUID object_id; + if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) + { + object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; + } + if (zoom) + { + // Make sure we are not increasing the distance between the camera and object + LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); + distance = llmin(distance, (F32) orig_distance.length()); + + gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), + LLSelectMgr::getInstance()->getSelectionCenterGlobal(), + object_id ); + + } + else + { + gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); + } + } } void handle_zoom_to_object(LLUUID object_id) { - const F32 PADDING_FACTOR = 2.f; + const F32 PADDING_FACTOR = 2.f; - LLViewerObject* object = gObjectList.findObject(object_id); + LLViewerObject* object = gObjectList.findObject(object_id); - if (object) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + if (object) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - LLBBox bbox = object->getBoundingBoxAgent() ; - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); + LLBBox bbox = object->getBoundingBoxAgent() ; + F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); + F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); - obj_to_cam.normVec(); + LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); + obj_to_cam.normVec(); - LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); + LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); - gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), - object_center_global, - object_id ); - } + gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), + object_center_global, + object_id ); + } } class LLAvatarInviteToGroup : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::inviteToGroup(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::inviteToGroup(avatar->getID()); + } + return true; + } }; class LLAvatarAddFriend : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !LLAvatarActions::isFriend(avatar->getID())) - { - request_friendship(avatar->getID()); - } - return true; - } -}; - - + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar && !LLAvatarActions::isFriend(avatar->getID())) + { + request_friendship(avatar->getID()); + } + return true; + } +}; + + class LLAvatarToggleMyProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID()); - if (LLFloater::isMinimized(instance)) - { - instance->setMinimized(FALSE); - instance->setFocus(TRUE); - } - else if (!LLFloater::isShown(instance)) - { - LLAvatarActions::showProfile(gAgent.getID()); - } - else if (!instance->hasFocus() && !instance->getIsChrome()) - { - instance->setFocus(TRUE); - } - else - { - instance->closeFloater(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID()); + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + } + else if (!LLFloater::isShown(instance)) + { + LLAvatarActions::showProfile(gAgent.getID()); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } + return true; + } }; class LLAvatarTogglePicks : public view_listener_t @@ -6495,41 +6495,41 @@ class LLAvatarTogglePicks : public view_listener_t class LLAvatarToggleSearch : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* instance = LLFloaterReg::findInstance("search"); - if (LLFloater::isMinimized(instance)) - { - instance->setMinimized(FALSE); - instance->setFocus(TRUE); - } - else if (!LLFloater::isShown(instance)) - { - LLFloaterReg::showInstance("search"); - } - else if (!instance->hasFocus() && !instance->getIsChrome()) - { - instance->setFocus(TRUE); - } - else - { - instance->closeFloater(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* instance = LLFloaterReg::findInstance("search"); + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + } + else if (!LLFloater::isShown(instance)) + { + LLFloaterReg::showInstance("search"); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } + return true; + } }; class LLAvatarResetSkeleton: public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = NULL; LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (obj) { avatar = obj->getAvatar(); } - if(avatar) + if(avatar) { avatar->resetSkeleton(false); } @@ -6553,184 +6553,184 @@ class LLAvatarEnableResetSkeleton: public view_listener_t class LLAvatarResetSkeletonAndAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) - { - avatar->resetSkeleton(true); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + return true; + } }; class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) - { - avatar->resetSkeleton(true); - } - else - { - gAgentAvatarp->resetSkeleton(true); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + else + { + gAgentAvatarp->resetSkeleton(true); + } + return true; + } }; class LLAvatarAddContact : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - create_inventory_callingcard(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + create_inventory_callingcard(avatar->getID()); + } + return true; + } }; bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - gAgent.setDoNotDisturb(false); - } - - LLViewerObject* objectp = selection->getPrimaryObject(); - - // Show avatar's name if paying attachment - if (objectp && objectp->isAttachment()) - { - while (objectp && !objectp->isAvatar()) - { - objectp = (LLViewerObject*)objectp->getParent(); - } - } - - if (objectp) - { - if (objectp->isAvatar()) - { - const bool is_group = false; - LLFloaterPayUtil::payDirectly(&give_money, - objectp->getID(), - is_group); - } - else - { - LLFloaterPayUtil::payViaObject(&give_money, selection); - } - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + gAgent.setDoNotDisturb(false); + } + + LLViewerObject* objectp = selection->getPrimaryObject(); + + // Show avatar's name if paying attachment + if (objectp && objectp->isAttachment()) + { + while (objectp && !objectp->isAvatar()) + { + objectp = (LLViewerObject*)objectp->getParent(); + } + } + + if (objectp) + { + if (objectp->isAvatar()) + { + const bool is_group = false; + LLFloaterPayUtil::payDirectly(&give_money, + objectp->getID(), + is_group); + } + else + { + LLFloaterPayUtil::payViaObject(&give_money, selection); + } + } + return false; } void handle_give_money_dialog() { - LLNotification::Params params("DoNotDisturbModePay"); - params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + LLNotification::Params params("DoNotDisturbModePay"); + params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); - if (gAgent.isDoNotDisturb()) - { - // warn users of being in do not disturb mode during a transaction - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 1); - } + if (gAgent.isDoNotDisturb()) + { + // warn users of being in do not disturb mode during a transaction + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 1); + } } bool enable_pay_avatar() { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLVOAvatar* avatar = find_avatar_from_object(obj); - return (avatar != NULL); + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLVOAvatar* avatar = find_avatar_from_object(obj); + return (avatar != NULL); } bool enable_pay_object() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if( object ) - { - LLViewerObject *parent = (LLViewerObject *)object->getParent(); - if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) - { - return true; - } - } - return false; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if( object ) + { + LLViewerObject *parent = (LLViewerObject *)object->getParent(); + if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) + { + return true; + } + } + return false; } bool enable_object_stand_up() { - // 'Object Stand Up' menu item is enabled when agent is sitting on selection - return sitting_on_selection(); + // 'Object Stand Up' menu item is enabled when agent is sitting on selection + return sitting_on_selection(); } bool enable_object_sit(LLUICtrl* ctrl) { - // 'Object Sit' menu item is enabled when agent is not sitting on selection - bool sitting_on_sel = sitting_on_selection(); - if (!sitting_on_sel) - { - // init default labels - init_default_item_label(ctrl); - - // Update label - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mSitName.empty()) - { - ctrl->setValue(node->mSitName); - } - else - { - ctrl->setValue(get_default_item_label(ctrl->getName())); - } - } - return !sitting_on_sel && is_object_sittable(); + // 'Object Sit' menu item is enabled when agent is not sitting on selection + bool sitting_on_sel = sitting_on_selection(); + if (!sitting_on_sel) + { + // init default labels + init_default_item_label(ctrl); + + // Update label + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mSitName.empty()) + { + ctrl->setValue(node->mSitName); + } + else + { + ctrl->setValue(get_default_item_label(ctrl->getName())); + } + } + return !sitting_on_sel && is_object_sittable(); } void dump_select_mgr(void*) { - LLSelectMgr::getInstance()->dump(); + LLSelectMgr::getInstance()->dump(); } void dump_inventory(void*) { - gInventory.dumpInventory(); + gInventory.dumpInventory(); } void handle_dump_followcam(void*) { - LLFollowCamMgr::getInstance()->dump(); + LLFollowCamMgr::getInstance()->dump(); } void handle_viewer_enable_message_log(void*) { - gMessageSystem->startLogging(); + gMessageSystem->startLogging(); } void handle_viewer_disable_message_log(void*) { - gMessageSystem->stopLogging(); + gMessageSystem->stopLogging(); } void handle_customize_avatar() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits")); } void handle_edit_outfit() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); } void handle_now_wearing() @@ -6747,225 +6747,225 @@ void handle_now_wearing() void handle_edit_shape() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_shape")); } void handle_hover_height() { - LLFloaterReg::showInstance("edit_hover_height"); + LLFloaterReg::showInstance("edit_hover_height"); } void handle_edit_physics() { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_physics")); + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_physics")); } void handle_report_abuse() { - // Prevent menu from appearing in screen shot. - gMenuHolder->hideMenus(); - LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); + // Prevent menu from appearing in screen shot. + gMenuHolder->hideMenus(); + LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); } void handle_buy_currency() { - LLBuyCurrencyHTML::openCurrencyFloater(); + LLBuyCurrencyHTML::openCurrencyFloater(); } class LLFloaterVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - bool new_value = false; - { - new_value = LLFloaterReg::instanceVisible(floater_name); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + bool new_value = false; + { + new_value = LLFloaterReg::instanceVisible(floater_name); + } + return new_value; + } }; class LLShowHelp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string help_topic = userdata.asString(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(help_topic); + return true; + } }; class LLToggleHelp : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); - if (help_browser && help_browser->isInVisibleChain()) - { - help_browser->closeFloater(); - } - else - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); + if (help_browser && help_browser->isInVisibleChain()) + { + help_browser->closeFloater(); + } + else + { + std::string help_topic = userdata.asString(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(help_topic); + } + return true; + } }; class LLToggleSpeak : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVoiceClient::getInstance()->toggleUserPTTState(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVoiceClient::getInstance()->toggleUserPTTState(); + return true; + } }; class LLShowSidetrayPanel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - - LLPanel* panel = LLFloaterSidePanelContainer::getPanel(floater_name); - if (panel) - { - if (panel->isInVisibleChain()) - { - LLFloaterReg::getInstance(floater_name)->closeFloater(); - } - else - { - LLFloaterReg::getInstance(floater_name)->openFloater(); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + + LLPanel* panel = LLFloaterSidePanelContainer::getPanel(floater_name); + if (panel) + { + if (panel->isInVisibleChain()) + { + LLFloaterReg::getInstance(floater_name)->closeFloater(); + } + else + { + LLFloaterReg::getInstance(floater_name)->openFloater(); + } + } + return true; + } }; class LLSidetrayPanelVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - // Toggle the panel - if (LLFloaterReg::getInstance(floater_name)->isInVisibleChain()) - { - return true; - } - else - { - return false; - } - - } + bool handleEvent(const LLSD& userdata) + { + std::string floater_name = userdata.asString(); + // Toggle the panel + if (LLFloaterReg::getInstance(floater_name)->isInVisibleChain()) + { + return true; + } + else + { + return false; + } + + } }; bool callback_show_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"].asString()); + } + return false; } class LLPromptShowURL : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string url = param.substr(offset+1); - - if (LLWeb::useExternalBrowser(url)) - { - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); - } - else - { - LLWeb::loadURL(url); - } - } - else - { - LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string url = param.substr(offset+1); + + if (LLWeb::useExternalBrowser(url)) + { + LLSD payload; + payload["url"] = url; + LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); + } + else + { + LLWeb::loadURL(url); + } + } + else + { + LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; + } + return true; + } }; bool callback_show_file(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"]); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"]); + } + return false; } class LLPromptShowFile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string file = param.substr(offset+1); - - LLSD payload; - payload["url"] = file; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); - } - else - { - LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string file = param.substr(offset+1); + + LLSD payload; + payload["url"] = file; + LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); + } + else + { + LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; + } + return true; + } }; class LLShowAgentProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - LLAvatarActions::showProfile(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID agent_id; + if (userdata.asString() == "agent") + { + agent_id = gAgent.getID(); + } + else if (userdata.asString() == "hit object") + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + agent_id = objectp->getID(); + } + } + else + { + agent_id = userdata.asUUID(); + } + + LLVOAvatar* avatar = find_avatar_from_object(agent_id); + if (avatar) + { + LLAvatarActions::showProfile(avatar->getID()); + } + return true; + } }; class LLShowAgentProfilePicks : public view_listener_t @@ -6979,164 +6979,164 @@ class LLShowAgentProfilePicks : public view_listener_t class LLToggleAgentProfile : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - if (!LLAvatarActions::profileVisible(avatar->getID())) - { - LLAvatarActions::showProfile(avatar->getID()); - } - else - { - LLAvatarActions::hideProfile(avatar->getID()); - } - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID agent_id; + if (userdata.asString() == "agent") + { + agent_id = gAgent.getID(); + } + else if (userdata.asString() == "hit object") + { + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + agent_id = objectp->getID(); + } + } + else + { + agent_id = userdata.asUUID(); + } + + LLVOAvatar* avatar = find_avatar_from_object(agent_id); + if (avatar) + { + if (!LLAvatarActions::profileVisible(avatar->getID())) + { + LLAvatarActions::showProfile(avatar->getID()); + } + else + { + LLAvatarActions::hideProfile(avatar->getID()); + } + } + return true; + } }; class LLLandEdit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) + { + // zoom in if we're looking at the avatar + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } + gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); + gViewerWindow->moveCursorToCenter(); + } + else if ( gSavedSettings.getBOOL("EditCameraMovement") ) + { + gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); + gViewerWindow->moveCursorToCenter(); + } - LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); + LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); - LLFloaterReg::showInstance("build"); + LLFloaterReg::showInstance("build"); - // Switch to land edit toolset - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); - return true; - } + // Switch to land edit toolset + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); + return true; + } }; class LLMuteParticle : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID; - - if (id.notNull()) - { - LLAvatarName av_name; - LLAvatarNameCache::get(id, &av_name); - - LLMute mute(id, av_name.getUserName(), LLMute::AGENT); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLUUID id = LLToolPie::getInstance()->getPick().mParticleOwnerID; + + if (id.notNull()) + { + LLAvatarName av_name; + LLAvatarNameCache::get(id, &av_name); + + LLMute mute(id, av_name.getUserName(), LLMute::AGENT); + if (LLMuteList::getInstance()->isMuted(mute.mID)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + } + + return true; + } }; class LLWorldEnableBuyLand : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->selectionEmpty() - ? LLViewerParcelMgr::getInstance()->getAgentParcel() - : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), - false); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( + LLViewerParcelMgr::getInstance()->selectionEmpty() + ? LLViewerParcelMgr::getInstance()->getAgentParcel() + : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), + false); + return new_value; + } }; BOOL enable_buy_land(void*) { - return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); + return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( + LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); } void handle_buy_land() { - LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); - if (vpm->selectionEmpty()) - { - vpm->selectParcelAt(gAgent.getPositionGlobal()); - } - vpm->startBuyLand(); + LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); + if (vpm->selectionEmpty()) + { + vpm->selectParcelAt(gAgent.getPositionGlobal()); + } + vpm->startBuyLand(); } class LLObjectAttachToAvatar : public view_listener_t { public: - LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} - static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } + LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} + static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } private: - bool handleEvent(const LLSD& userdata) - { - setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); - if (selectedObject) - { - S32 index = userdata.asInteger(); - LLViewerJointAttachment* attachment_point = NULL; - if (index > 0) - attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); - confirmReplaceAttachment(0, attachment_point); - } - return true; - } - - static void onNearAttachObject(BOOL success, void *user_data); - void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); - class CallbackData : public LLSelectionCallbackData - { - public: - CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} - - LLViewerJointAttachment* mAttachmentPoint; - bool mReplace; - }; + bool handleEvent(const LLSD& userdata) + { + setObjectSelection(LLSelectMgr::getInstance()->getSelection()); + LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); + if (selectedObject) + { + S32 index = userdata.asInteger(); + LLViewerJointAttachment* attachment_point = NULL; + if (index > 0) + attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + confirmReplaceAttachment(0, attachment_point); + } + return true; + } + + static void onNearAttachObject(BOOL success, void *user_data); + void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); + class CallbackData : public LLSelectionCallbackData + { + public: + CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} + + LLViewerJointAttachment* mAttachmentPoint; + bool mReplace; + }; protected: - static LLObjectSelectionHandle sObjectSelection; - bool mReplace; + static LLObjectSelectionHandle sObjectSelection; + bool mReplace; }; LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; @@ -7144,238 +7144,238 @@ LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; // static void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) { - if (!user_data) return; - CallbackData* cb_data = static_cast(user_data); - - if (success) - { - const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; - - U8 attachment_id = 0; - if (attachment) - { - for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) - { - if (iter->second == attachment) - { - attachment_id = iter->first; - break; - } - } - } - else - { - // interpret 0 as "default location" - attachment_id = 0; - } - LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); - } - LLObjectAttachToAvatar::setObjectSelection(NULL); - - delete cb_data; + if (!user_data) return; + CallbackData* cb_data = static_cast(user_data); + + if (success) + { + const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; + + U8 attachment_id = 0; + if (attachment) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) + { + if (iter->second == attachment) + { + attachment_id = iter->first; + break; + } + } + } + else + { + // interpret 0 as "default location" + attachment_id = 0; + } + LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); + } + LLObjectAttachToAvatar::setObjectSelection(NULL); + + delete cb_data; } // static void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point) { - if (option == 0/*YES*/) - { - LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); - if (selectedObject) - { - const F32 MIN_STOP_DISTANCE = 1.f; // meters - const F32 ARM_LENGTH = 0.5f; // meters - const F32 SCALE_FUDGE = 1.5f; - - F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; - if (stop_distance < MIN_STOP_DISTANCE) - { - stop_distance = MIN_STOP_DISTANCE; - } - - LLVector3 walkToSpot = selectedObject->getPositionAgent(); - - // make sure we stop in front of the object - LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); - delta.normVec(); - delta = delta * 0.5f; - walkToSpot -= delta; - - // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. - CallbackData* user_data = new CallbackData(attachment_point, mReplace); - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); - gAgentCamera.clearFocusObject(); - } - } + if (option == 0/*YES*/) + { + LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); + if (selectedObject) + { + const F32 MIN_STOP_DISTANCE = 1.f; // meters + const F32 ARM_LENGTH = 0.5f; // meters + const F32 SCALE_FUDGE = 1.5f; + + F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; + if (stop_distance < MIN_STOP_DISTANCE) + { + stop_distance = MIN_STOP_DISTANCE; + } + + LLVector3 walkToSpot = selectedObject->getPositionAgent(); + + // make sure we stop in front of the object + LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); + delta.normVec(); + delta = delta * 0.5f; + walkToSpot -= delta; + + // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. + CallbackData* user_data = new CallbackData(attachment_point, mReplace); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); + gAgentCamera.clearFocusObject(); + } + } } void callback_attachment_drop(const LLSD& notification, const LLSD& response) { - // Ensure user confirmed the drop - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; - - // Called when the user clicked on an object attached to them - // and selected "Drop". - LLUUID object_id = notification["payload"]["object_id"].asUUID(); - LLViewerObject *object = gObjectList.findObject(object_id); - - if (!object) - { - LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; - return; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return; - } - - if (object->isAvatar()) - { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; - return; - } - - // reselect the object - LLSelectMgr::getInstance()->selectObjectAndFamily(object); - - LLSelectMgr::getInstance()->sendDropAttachment(); - - return; + // Ensure user confirmed the drop + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; + + // Called when the user clicked on an object attached to them + // and selected "Drop". + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLViewerObject *object = gObjectList.findObject(object_id); + + if (!object) + { + LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; + return; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return; + } + + if (object->isAvatar()) + { + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + return; + } + + // reselect the object + LLSelectMgr::getInstance()->selectObjectAndFamily(object); + + LLSelectMgr::getInstance()->sendDropAttachment(); + + return; } class LLAttachmentDrop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSD payload; - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + bool handleEvent(const LLSD& userdata) + { + LLSD payload; + LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (object) - { - payload["object_id"] = object->getID(); - } - else - { - LL_WARNS() << "Drop object not found" << LL_ENDL; - return true; - } + if (object) + { + payload["object_id"] = object->getID(); + } + else + { + LL_WARNS() << "Drop object not found" << LL_ENDL; + return true; + } - LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); - return true; - } + LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); + return true; + } }; // called from avatar pie menu class LLAttachmentDetachFromPoint : public view_listener_t { - bool handleEvent(const LLSD& user_data) - { - uuid_vec_t ids_to_remove; - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment->getNumObjects() > 0) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); - iter != attachment->mAttachedObjects.end(); - iter++) - { - LLViewerObject *attached_object = iter->get(); - ids_to_remove.push_back(attached_object->getAttachmentItemID()); - } - } - if (!ids_to_remove.empty()) - { - LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove); - } - return true; - } + bool handleEvent(const LLSD& user_data) + { + uuid_vec_t ids_to_remove; + const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); + if (attachment->getNumObjects() > 0) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); + iter != attachment->mAttachedObjects.end(); + iter++) + { + LLViewerObject *attached_object = iter->get(); + ids_to_remove.push_back(attached_object->getAttachmentItemID()); + } + } + if (!ids_to_remove.empty()) + { + LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove); + } + return true; + } }; static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { - std::string label; - LLMenuItemGL* menu = dynamic_cast(ctrl); - if (menu) - { - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment) - { - label = data["label"].asString(); - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = attachment_iter->get(); - if (attached_object) - { - LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); - if (itemp) - { - label += std::string(" (") + itemp->getName() + std::string(")"); - break; - } - } - } - } - menu->setLabel(label); - } - return true; + std::string label; + LLMenuItemGL* menu = dynamic_cast(ctrl); + if (menu) + { + const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); + if (attachment) + { + label = data["label"].asString(); + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object) + { + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); + if (itemp) + { + label += std::string(" (") + itemp->getName() + std::string(")"); + break; + } + } + } + } + menu->setLabel(label); + } + return true; } class LLAttachmentDetach : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // Called when the user clicked on an object attached to them - // and selected "Detach". - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return true; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; - return true; - } - - if (object->isAvatar()) - { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; - return true; - } - - LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); - - return true; - } + bool handleEvent(const LLSD& userdata) + { + // Called when the user clicked on an object attached to them + // and selected "Detach". + LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return true; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object) + { + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + return true; + } + + if (object->isAvatar()) + { + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + return true; + } + + LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); + + return true; + } }; //Adding an observer for a Jira 2422 and needs to be a fetch observer @@ -7383,468 +7383,468 @@ class LLAttachmentDetach : public view_listener_t class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver { public: - LLWornItemFetchedObserver(const LLUUID& worn_item_id) : - LLInventoryFetchItemsObserver(worn_item_id) - {} - virtual ~LLWornItemFetchedObserver() {} + LLWornItemFetchedObserver(const LLUUID& worn_item_id) : + LLInventoryFetchItemsObserver(worn_item_id) + {} + virtual ~LLWornItemFetchedObserver() {} protected: - virtual void done() - { - gMenuAttachmentSelf->buildDrawLabels(); - gInventory.removeObserver(this); - delete this; - } + virtual void done() + { + gMenuAttachmentSelf->buildDrawLabels(); + gInventory.removeObserver(this); + delete this; + } }; // You can only drop items on parcels where you can build. class LLAttachmentEnableDrop : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); - - //Add an inventory observer to only allow dropping the newly attached item - //once it exists in your inventory. Look at Jira 2422. - //-jwolk - - // A bug occurs when you wear/drop an item before it actively is added to your inventory - // if this is the case (you're on a slow sim, etc.) a copy of the object, - // well, a newly created object with the same properties, is placed - // in your inventory. Therefore, we disable the drop option until the - // item is in your inventory - - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLViewerJointAttachment* attachment = NULL; - LLInventoryItem* item = NULL; - - // Do not enable drop if all faces of object are not enabled - if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); - attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); - - if (attachment) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) - // so check to see if the item is in the inventory already - item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); - if (!item) - { - // Item does not exist, make an observer to enable the pie menu - // when the item finishes fetching worst case scenario - // if a fetch is already out there (being sent from a slow sim) - // we refetch and there are 2 fetches - LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); - worn_item_fetched->startFetch(); - gInventory.addObserver(worn_item_fetched); - } - } - } - } - - //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach() && can_build && item; - - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); + + //Add an inventory observer to only allow dropping the newly attached item + //once it exists in your inventory. Look at Jira 2422. + //-jwolk + + // A bug occurs when you wear/drop an item before it actively is added to your inventory + // if this is the case (you're on a slow sim, etc.) a copy of the object, + // well, a newly created object with the same properties, is placed + // in your inventory. Therefore, we disable the drop option until the + // item is in your inventory + + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLViewerJointAttachment* attachment = NULL; + LLInventoryItem* item = NULL; + + // Do not enable drop if all faces of object are not enabled + if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); + attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); + + if (attachment) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) + // so check to see if the item is in the inventory already + item = gInventory.getItem(attachment_iter->get()->getAttachmentItemID()); + if (!item) + { + // Item does not exist, make an observer to enable the pie menu + // when the item finishes fetching worst case scenario + // if a fetch is already out there (being sent from a slow sim) + // we refetch and there are 2 fetches + LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); + worn_item_fetched->startFetch(); + gInventory.addObserver(worn_item_fetched); + } + } + } + } + + //now check to make sure that the item is actually in the inventory before we enable dropping it + bool new_value = enable_detach() && can_build && item; + + return new_value; + } }; BOOL enable_detach(const LLSD&) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - // Only enable detach if all faces of object are selected - if (!object || - !object->isAttachment() || - !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - return FALSE; - } + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - // Find the avatar who owns this attachment - LLViewerObject* avatar = object; - while (avatar) - { - // ...if it's you, good to detach - if (avatar->getID() == gAgent.getID()) - { - return TRUE; - } + // Only enable detach if all faces of object are selected + if (!object || + !object->isAttachment() || + !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) + { + return FALSE; + } - avatar = (LLViewerObject*)avatar->getParent(); - } + // Find the avatar who owns this attachment + LLViewerObject* avatar = object; + while (avatar) + { + // ...if it's you, good to detach + if (avatar->getID() == gAgent.getID()) + { + return TRUE; + } + + avatar = (LLViewerObject*)avatar->getParent(); + } - return FALSE; + return FALSE; } class LLAttachmentEnableDetach : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_detach(); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_detach(); + return new_value; + } }; // Used to tell if the selected object can be attached to your avatar. BOOL object_selected_and_point_valid() { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::root_iterator iter = selection->root_begin(); - iter != selection->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerObject::const_child_list_t& child_list = object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - if (child->isAvatar()) - { - return FALSE; - } - } - } - - return (selection->getRootObjectCount() == 1) && - (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && - selection->getFirstRootObject()->permYouOwner() && - selection->getFirstRootObject()->flagObjectMove() && - !selection->getFirstRootObject()->flagObjectPermanent() && - !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && - (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::root_iterator iter = selection->root_begin(); + iter != selection->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + LLViewerObject::const_child_list_t& child_list = object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + if (child->isAvatar()) + { + return FALSE; + } + } + } + + return (selection->getRootObjectCount() == 1) && + (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && + selection->getFirstRootObject()->permYouOwner() && + selection->getFirstRootObject()->flagObjectMove() && + !selection->getFirstRootObject()->flagObjectPermanent() && + !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && + (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); } BOOL object_is_wearable() { - if (!isAgentAvatarValid()) - { - return FALSE; - } - if (!object_selected_and_point_valid()) - { - return FALSE; - } - if (sitting_on_selection()) - { - return FALSE; - } + if (!isAgentAvatarValid()) + { + return FALSE; + } + if (!object_selected_and_point_valid()) + { + return FALSE; + } + if (sitting_on_selection()) + { + return FALSE; + } if (!gAgentAvatarp->canAttachMoreObjects()) { return FALSE; } - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - if (node->mPermissions->getOwner() == gAgent.getID()) - { - return TRUE; - } - } - return FALSE; + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) + { + LLSelectNode* node = *iter; + if (node->mPermissions->getOwner() == gAgent.getID()) + { + return TRUE; + } + } + return FALSE; } class LLAttachmentPointFilled : public view_listener_t { - bool handleEvent(const LLSD& user_data) - { - bool enable = false; - LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); - if (found_it != gAgentAvatarp->mAttachmentPoints.end()) - { - enable = found_it->second->getNumObjects() > 0; - } - return enable; - } + bool handleEvent(const LLSD& user_data) + { + bool enable = false; + LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); + if (found_it != gAgentAvatarp->mAttachmentPoints.end()) + { + enable = found_it->second->getNumObjects() > 0; + } + return enable; + } }; class LLAvatarSendIM : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startIM(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::startIM(avatar->getID()); + } + return true; + } }; class LLAvatarCall : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startCall(avatar->getID()); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLAvatarActions::startCall(avatar->getID()); + } + return true; + } }; namespace { - struct QueueObjects : public LLSelectedNodeFunctor - { - BOOL scripted; - BOOL modifiable; - LLFloaterScriptQueue* mQueue; - QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLSelectNode* node) - { - LLViewerObject* obj = node->getObject(); - if (!obj) - { - return true; - } - scripted = obj->flagScripted(); - modifiable = obj->permModify(); - - if( scripted && modifiable ) - { - mQueue->addObject(obj->getID(), node->mName); - return false; - } - else - { - return true; // fail: stop applying - } - } - }; + struct QueueObjects : public LLSelectedNodeFunctor + { + BOOL scripted; + BOOL modifiable; + LLFloaterScriptQueue* mQueue; + QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} + virtual bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + if (!obj) + { + return true; + } + scripted = obj->flagScripted(); + modifiable = obj->permModify(); + + if( scripted && modifiable ) + { + mQueue->addObject(obj->getID(), node->mName); + return false; + } + else + { + return true; // fail: stop applying + } + } + }; } bool queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { - QueueObjects func(q); - LLSelectMgr *mgr = LLSelectMgr::getInstance(); - LLObjectSelectionHandle selectHandle = mgr->getSelection(); - bool fail = selectHandle->applyToNodes(&func); - if(fail) - { - if ( !func.scripted ) - { - std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; - LLNotificationsUtil::add(noscriptmsg); - } - else if ( !func.modifiable ) - { - std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; - LLNotificationsUtil::add(nomodmsg); - } - else - { - LL_ERRS() << "Bad logic." << LL_ENDL; - } - q->closeFloater(); - } - else - { - if (!q->start()) - { - LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; - } - } - return !fail; + QueueObjects func(q); + LLSelectMgr *mgr = LLSelectMgr::getInstance(); + LLObjectSelectionHandle selectHandle = mgr->getSelection(); + bool fail = selectHandle->applyToNodes(&func); + if(fail) + { + if ( !func.scripted ) + { + std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; + LLNotificationsUtil::add(noscriptmsg); + } + else if ( !func.modifiable ) + { + std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; + LLNotificationsUtil::add(nomodmsg); + } + else + { + LL_ERRS() << "Bad logic." << LL_ENDL; + } + q->closeFloater(); + } + else + { + if (!q->start()) + { + LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; + } + } + return !fail; } class LLToolsSelectedScriptAction : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string action = userdata.asString(); - bool mono = false; - std::string msg, name; - std::string title; - if (action == "compile mono") - { - name = "compile_queue"; - mono = true; - msg = "Recompile"; - title = LLTrans::getString("CompileQueueTitle"); - } - if (action == "compile lsl") - { - name = "compile_queue"; - msg = "Recompile"; - title = LLTrans::getString("CompileQueueTitle"); - } - else if (action == "reset") - { - name = "reset_queue"; - msg = "Reset"; - title = LLTrans::getString("ResetQueueTitle"); - } - else if (action == "start") - { - name = "start_queue"; - msg = "SetRunning"; - title = LLTrans::getString("RunQueueTitle"); - } - else if (action == "stop") - { - name = "stop_queue"; - msg = "SetRunningNot"; - title = LLTrans::getString("NotRunQueueTitle"); - } - LLUUID id; id.generate(); - - LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance(name, LLSD(id)); - if (queue) - { - queue->setMono(mono); - if (queue_actions(queue, msg)) - { - queue->setTitle(title); - } - } - else - { - LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string action = userdata.asString(); + bool mono = false; + std::string msg, name; + std::string title; + if (action == "compile mono") + { + name = "compile_queue"; + mono = true; + msg = "Recompile"; + title = LLTrans::getString("CompileQueueTitle"); + } + if (action == "compile lsl") + { + name = "compile_queue"; + msg = "Recompile"; + title = LLTrans::getString("CompileQueueTitle"); + } + else if (action == "reset") + { + name = "reset_queue"; + msg = "Reset"; + title = LLTrans::getString("ResetQueueTitle"); + } + else if (action == "start") + { + name = "start_queue"; + msg = "SetRunning"; + title = LLTrans::getString("RunQueueTitle"); + } + else if (action == "stop") + { + name = "stop_queue"; + msg = "SetRunningNot"; + title = LLTrans::getString("NotRunQueueTitle"); + } + LLUUID id; id.generate(); + + LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance(name, LLSD(id)); + if (queue) + { + queue->setMono(mono); + if (queue_actions(queue, msg)) + { + queue->setTitle(title); + } + } + else + { + LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; + } + return true; + } }; void handle_selected_texture_info(void*) { - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Texture info for: "); - msg.append(node->mName); - - U8 te_count = node->getObject()->getNumTEs(); - // map from texture ID to list of faces using it - typedef std::map< LLUUID, std::vector > map_t; - map_t faces_per_texture; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - LLViewerTexture* img = node->getObject()->getTEImage(i); - LLUUID image_id = img->getID(); - faces_per_texture[image_id].push_back(i); - } - // Per-texture, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) - { - U8 te = it->second[0]; - LLViewerTexture* img = node->getObject()->getTEImage(te); - S32 height = img->getHeight(); - S32 width = img->getWidth(); - S32 components = img->getComponents(); - msg.append(llformat("\n%dx%d %s on face ", - width, - height, - (components == 4 ? "alpha" : "opaque"))); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - } - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } + for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + LLSelectNode* node = *iter; + + std::string msg; + msg.assign("Texture info for: "); + msg.append(node->mName); + + U8 te_count = node->getObject()->getNumTEs(); + // map from texture ID to list of faces using it + typedef std::map< LLUUID, std::vector > map_t; + map_t faces_per_texture; + for (U8 i = 0; i < te_count; i++) + { + if (!node->isTESelected(i)) continue; + + LLViewerTexture* img = node->getObject()->getTEImage(i); + LLUUID image_id = img->getID(); + faces_per_texture[image_id].push_back(i); + } + // Per-texture, dump which faces are using it. + map_t::iterator it; + for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) + { + U8 te = it->second[0]; + LLViewerTexture* img = node->getObject()->getTEImage(te); + S32 height = img->getHeight(); + S32 width = img->getWidth(); + S32 components = img->getComponents(); + msg.append(llformat("\n%dx%d %s on face ", + width, + height, + (components == 4 ? "alpha" : "opaque"))); + for (U8 i = 0; i < it->second.size(); ++i) + { + msg.append( llformat("%d ", (S32)(it->second[i]))); + } + } + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); + } } void handle_selected_material_info() { - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Material info for: \n"); - msg.append(node->mName); - - U8 te_count = node->getObject()->getNumTEs(); - // map from material ID to list of faces using it - typedef std::map > map_t; - map_t faces_per_material; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID(); - faces_per_material[material_id].push_back(i); - } - // Per-material, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it) - { - const LLMaterialID& material_id = it->first; - msg += llformat("%s on face ", material_id.asString().c_str()); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - msg.append("\n"); - } - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } + for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + LLSelectNode* node = *iter; + + std::string msg; + msg.assign("Material info for: \n"); + msg.append(node->mName); + + U8 te_count = node->getObject()->getNumTEs(); + // map from material ID to list of faces using it + typedef std::map > map_t; + map_t faces_per_material; + for (U8 i = 0; i < te_count; i++) + { + if (!node->isTESelected(i)) continue; + + const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID(); + faces_per_material[material_id].push_back(i); + } + // Per-material, dump which faces are using it. + map_t::iterator it; + for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it) + { + const LLMaterialID& material_id = it->first; + msg += llformat("%s on face ", material_id.asString().c_str()); + for (U8 i = 0; i < it->second.size(); ++i) + { + msg.append( llformat("%d ", (S32)(it->second[i]))); + } + msg.append("\n"); + } + + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); + } } void handle_test_male(void*) { - LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); - //gGestureList.requestResetFromServer( TRUE ); + LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); + //gGestureList.requestResetFromServer( TRUE ); } void handle_test_female(void*) { - LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); - //gGestureList.requestResetFromServer( FALSE ); + LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); + //gGestureList.requestResetFromServer( FALSE ); } void handle_dump_attachments(void*) { - if(!isAgentAvatarValid()) return; - - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - S32 key = curiter->first; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = attachment_iter->get(); - BOOL visible = (attached_object != NULL && - attached_object->mDrawable.notNull() && - !attached_object->mDrawable->isRenderType(0)); - LLVector3 pos; - if (visible) pos = attached_object->mDrawable->getPosition(); - LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() - << (attached_object ? " present " : " absent ") - << (visible ? "visible " : "invisible ") - << " at " << pos - << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) - << LL_ENDL; - } - } + if(!isAgentAvatarValid()) return; + + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + S32 key = curiter->first; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = attachment_iter->get(); + BOOL visible = (attached_object != NULL && + attached_object->mDrawable.notNull() && + !attached_object->mDrawable->isRenderType(0)); + LLVector3 pos; + if (visible) pos = attached_object->mDrawable->getPosition(); + LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() + << (attached_object ? " present " : " absent ") + << (visible ? "visible " : "invisible ") + << " at " << pos + << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) + << LL_ENDL; + } + } } @@ -7853,369 +7853,369 @@ class LLToggleControl : public view_listener_t { protected: - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); + return true; + } }; class LLCheckControl : public view_listener_t { - bool handleEvent( const LLSD& userdata) - { - std::string callback_data = userdata.asString(); - bool new_value = gSavedSettings.getBOOL(callback_data); - return new_value; - } + bool handleEvent( const LLSD& userdata) + { + std::string callback_data = userdata.asString(); + bool new_value = gSavedSettings.getBOOL(callback_data); + return new_value; + } }; // not so generic class LLAdvancedCheckRenderShadowOption: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // is off - { - return false; - } - else // is on - { - return true; - } - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + S32 current_shadow_level = gSavedSettings.getS32(control_name); + if (current_shadow_level == 0) // is off + { + return false; + } + else // is on + { + return true; + } + } }; class LLAdvancedClickRenderShadowOption: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // upgrade to level 2 - { - gSavedSettings.setS32(control_name, 2); - } - else // downgrade to level 0 - { - gSavedSettings.setS32(control_name, 0); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + S32 current_shadow_level = gSavedSettings.getS32(control_name); + if (current_shadow_level == 0) // upgrade to level 2 + { + gSavedSettings.setS32(control_name, 2); + } + else // downgrade to level 0 + { + gSavedSettings.setS32(control_name, 0); + } + return true; + } }; class LLAdvancedClickRenderProfile: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gShaderProfileFrame = TRUE; - return true; - } + bool handleEvent(const LLSD& userdata) + { + gShaderProfileFrame = TRUE; + return true; + } }; F32 gpu_benchmark(); class LLAdvancedClickRenderBenchmark: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gpu_benchmark(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gpu_benchmark(); + return true; + } }; // these are used in the gl menus to set control values that require shader recompilation class LLToggleShaderControl : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); + BOOL checked = gSavedSettings.getBOOL( control_name ); + gSavedSettings.setBOOL( control_name, !checked ); LLPipeline::refreshCachedSettings(); LLViewerShaderMgr::instance()->setShaders(); - return !checked; - } + return !checked; + } }; void menu_toggle_attached_lights(void* user_data) { - LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); + LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); } void menu_toggle_attached_particles(void* user_data) { - LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } class LLAdvancedHandleAttachedLightParticles: public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); - // toggle the control - gSavedSettings.setBOOL(control_name, - !gSavedSettings.getBOOL(control_name)); + // toggle the control + gSavedSettings.setBOOL(control_name, + !gSavedSettings.getBOOL(control_name)); - // update internal flags - if (control_name == "RenderAttachedLights") - { - menu_toggle_attached_lights(NULL); - } - else if (control_name == "RenderAttachedParticles") - { - menu_toggle_attached_particles(NULL); - } - return true; - } + // update internal flags + if (control_name == "RenderAttachedLights") + { + menu_toggle_attached_lights(NULL); + } + else if (control_name == "RenderAttachedParticles") + { + menu_toggle_attached_particles(NULL); + } + return true; + } }; class LLSomethingSelected : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); + return new_value; + } }; class LLSomethingSelectedNoHUD : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); + return new_value; + } }; static bool is_editable_selected() { - return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); } class LLEditableSelected : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return is_editable_selected(); - } + bool handleEvent(const LLSD& userdata) + { + return is_editable_selected(); + } }; class LLEditableSelectedMono : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - LLViewerRegion* region = gAgent.getRegion(); - if(region && gMenuHolder) - { - bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); - new_value = is_editable_selected() && have_cap; - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = false; + LLViewerRegion* region = gAgent.getRegion(); + if(region && gMenuHolder) + { + bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); + new_value = is_editable_selected() && have_cap; + } + return new_value; + } }; bool enable_object_take_copy() { - bool all_valid = false; - if (LLSelectMgr::getInstance()) - { - if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 0) - { - all_valid = true; + bool all_valid = false; + if (LLSelectMgr::getInstance()) + { + if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 0) + { + all_valid = true; #ifndef HACKED_GODLIKE_VIEWER # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (LLGridManager::getInstance()->isInProductionGrid() + if (LLGridManager::getInstance()->isInProductionGrid() || !gAgent.isGodlike()) # endif - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return (!obj->permCopy() || obj->isAttachment()); - } - } func; - const bool firstonly = true; - bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - all_valid = !any_invalid; - } + { + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* obj) + { + return (!obj->permCopy() || obj->isAttachment()); + } + } func; + const bool firstonly = true; + bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); + all_valid = !any_invalid; + } #endif // HACKED_GODLIKE_VIEWER - } - } + } + } - return all_valid; + return all_valid; } class LLHasAsset : public LLInventoryCollectFunctor { public: - LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} - virtual ~LLHasAsset() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL hasAsset() const { return mHasAsset; } + LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} + virtual ~LLHasAsset() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + BOOL hasAsset() const { return mHasAsset; } protected: - LLUUID mAssetID; - BOOL mHasAsset; + LLUUID mAssetID; + BOOL mHasAsset; }; bool LLHasAsset::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + LLInventoryItem* item) { - if(item && item->getAssetUUID() == mAssetID) - { - mHasAsset = TRUE; - } - return FALSE; + if(item && item->getAssetUUID() == mAssetID) + { + mHasAsset = TRUE; + } + return FALSE; } BOOL enable_save_into_task_inventory(void*) { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - LLViewerObject* obj = node->getObject(); - if( obj && !obj->isAttachment() ) - { - return TRUE; - } - } - return FALSE; + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if(node && (node->mValid) && (!node->mFromTaskID.isNull())) + { + // *TODO: check to see if the fromtaskid object exists. + LLViewerObject* obj = node->getObject(); + if( obj && !obj->isAttachment() ) + { + return TRUE; + } + } + return FALSE; } class LLToolsEnableSaveToObjectInventory : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_save_into_task_inventory(NULL); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_save_into_task_inventory(NULL); + return new_value; + } }; class LLToggleHowTo : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::toggleInstanceOrBringToFront("guidebook"); + return true; + } }; class LLViewEnableMouselook : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // You can't go directly from customize avatar to mouselook. - // TODO: write code with appropriate dialogs to handle this transition. - bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + // You can't go directly from customize avatar to mouselook. + // TODO: write code with appropriate dialogs to handle this transition. + bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); + return new_value; + } }; class LLToolsEnableToolNotPie : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); + return new_value; + } }; class LLWorldEnableCreateLandmark : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return !LLLandmarkActions::landmarkAlreadyExists(); - } + bool handleEvent(const LLSD& userdata) + { + return !LLLandmarkActions::landmarkAlreadyExists(); + } }; class LLWorldEnableSetHomeLocation : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.isGodlike() || - (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAgent.isGodlike() || + (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); + return new_value; + } }; class LLWorldEnableTeleportHome : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLViewerRegion* regionp = gAgent.getRegion(); - bool agent_on_prelude = (regionp && regionp->isPrelude()); - bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; - return enable_teleport_home; - } + bool handleEvent(const LLSD& userdata) + { + LLViewerRegion* regionp = gAgent.getRegion(); + bool agent_on_prelude = (regionp && regionp->isPrelude()); + bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; + return enable_teleport_home; + } }; BOOL enable_god_full(void*) { - return gAgent.getGodLevel() >= GOD_FULL; + return gAgent.getGodLevel() >= GOD_FULL; } BOOL enable_god_liaison(void*) { - return gAgent.getGodLevel() >= GOD_LIAISON; + return gAgent.getGodLevel() >= GOD_LIAISON; } bool is_god_customer_service() { - return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; + return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; } BOOL enable_god_basic(void*) { - return gAgent.getGodLevel() > GOD_NOT; + return gAgent.getGodLevel() > GOD_NOT; } void toggle_show_xui_names(void *) { - gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); + gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); } BOOL check_show_xui_names(void *) { - return gSavedSettings.getBOOL("DebugShowXUINames"); + return gSavedSettings.getBOOL("DebugShowXUINames"); } class LLToolsSelectOnlyMyObjects : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); - gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); + gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); - return true; - } + return true; + } }; class LLToolsSelectOnlyMovableObjects : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); - gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); + gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); - return true; - } + return true; + } }; class LLToolsSelectInvisibleObjects : public view_listener_t @@ -8244,178 +8244,178 @@ class LLToolsSelectReflectionProbes: public view_listener_t class LLToolsSelectBySurrounding : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; + bool handleEvent(const LLSD& userdata) + { + LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; - gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); - return true; - } + gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); + return true; + } }; class LLToolsShowHiddenSelection : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // TomY TODO Merge these - LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; + bool handleEvent(const LLSD& userdata) + { + // TomY TODO Merge these + LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; - gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); - return true; - } + gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); + return true; + } }; class LLToolsShowSelectionLightRadius : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - // TomY TODO merge these - LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; + bool handleEvent(const LLSD& userdata) + { + // TomY TODO merge these + LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; - gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); - return true; - } + gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); + return true; + } }; class LLToolsEditLinkedParts : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); - gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); - if (select_individuals) - { - LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); - } - else - { - LLSelectMgr::getInstance()->promoteSelectionToRoot(); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); + gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); + if (select_individuals) + { + LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); + } + else + { + LLSelectMgr::getInstance()->promoteSelectionToRoot(); + } + return true; + } }; void reload_vertex_shader(void *) { - //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP + //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP } void handle_dump_avatar_local_textures(void*) { - gAgentAvatarp->dumpLocalTextures(); + gAgentAvatarp->dumpLocalTextures(); } void handle_dump_timers() { - LLTrace::BlockTimer::dumpCurTimes(); + LLTrace::BlockTimer::dumpCurTimes(); } void handle_debug_avatar_textures(void*) { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); - } + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); + } } void handle_grab_baked_texture(void* data) { - EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); - if (!isAgentAvatarValid()) return; - - const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); - LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << LL_ENDL; - LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; - LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - if(folder_id.notNull()) - { - std::string name; - name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; - - LLUUID item_id; - item_id.generate(); - LLPermissions perm; - perm.init(gAgentID, - gAgentID, - LLUUID::null, - LLUUID::null); - U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; - perm.initMasks(PERM_ALL, - PERM_ALL, - PERM_NONE, - PERM_NONE, - next_owner_perm); - time_t creation_date_now = time_corrected(); - LLPointer item - = new LLViewerInventoryItem(item_id, - folder_id, - perm, - asset_id, - asset_type, - inv_type, - name, - LLStringUtil::null, - LLSaleInfo::DEFAULT, - LLInventoryItemFlags::II_FLAGS_NONE, - creation_date_now); - - item->updateServer(TRUE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - // Show the preview panel for textures to let - // user know that the image is now in inventory. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if(active_panel) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - active_panel->openSelected(); - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); - } - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } + EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); + if (!isAgentAvatarValid()) return; + + const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); + LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << LL_ENDL; + LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; + LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); + if(folder_id.notNull()) + { + std::string name; + name = "Baked " + LLAvatarAppearance::getDictionary()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; + + LLUUID item_id; + item_id.generate(); + LLPermissions perm; + perm.init(gAgentID, + gAgentID, + LLUUID::null, + LLUUID::null); + U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; + perm.initMasks(PERM_ALL, + PERM_ALL, + PERM_NONE, + PERM_NONE, + next_owner_perm); + time_t creation_date_now = time_corrected(); + LLPointer item + = new LLViewerInventoryItem(item_id, + folder_id, + perm, + asset_id, + asset_type, + inv_type, + name, + LLStringUtil::null, + LLSaleInfo::DEFAULT, + LLInventoryItemFlags::II_FLAGS_NONE, + creation_date_now); + + item->updateServer(TRUE); + gInventory.updateItem(item); + gInventory.notifyObservers(); + + // Show the preview panel for textures to let + // user know that the image is now in inventory. + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if(active_panel) + { + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); + + active_panel->setSelection(item_id, TAKE_FOCUS_NO); + active_panel->openSelected(); + //LLFloaterInventory::dumpSelectionInformation((void*)view); + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus_ctrl); + } + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } } BOOL enable_grab_baked_texture(void* data) { - EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); - if (isAgentAvatarValid()) - { - return gAgentAvatarp->canGrabBakedTexture(index); - } - return FALSE; + EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); + if (isAgentAvatarValid()) + { + return gAgentAvatarp->canGrabBakedTexture(index); + } + return FALSE; } // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) { - if (object) - { - if( object->isAttachment() ) - { - do - { - object = (LLViewerObject*) object->getParent(); - } - while( object && !object->isAvatar() ); - } - else if( !object->isAvatar() ) - { - object = NULL; - } - } + if (object) + { + if( object->isAttachment() ) + { + do + { + object = (LLViewerObject*) object->getParent(); + } + while( object && !object->isAvatar() ); + } + else if( !object->isAvatar() ) + { + object = NULL; + } + } - return (LLVOAvatar*) object; + return (LLVOAvatar*) object; } @@ -8423,13 +8423,13 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ) { - return find_avatar_from_object( gObjectList.findObject(object_id) ); + return find_avatar_from_object( gObjectList.findObject(object_id) ); } void handle_disconnect_viewer(void *) { - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); } void force_error_breakpoint(void *) @@ -8484,30 +8484,30 @@ void force_error_thread_crash(void *) class LLToolsUseSelectionForGrid : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::getInstance()->clearGridObjects(); - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* objectp) - { - LLSelectMgr::getInstance()->addGridObject(objectp); - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); - LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); - LLFloaterTools::setGridMode((S32)GRID_MODE_REF_OBJECT); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLSelectMgr::getInstance()->clearGridObjects(); + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* objectp) + { + LLSelectMgr::getInstance()->addGridObject(objectp); + return true; + } + } func; + LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); + LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); + LLFloaterTools::setGridMode((S32)GRID_MODE_REF_OBJECT); + return true; + } }; void handle_test_load_url(void*) { - LLWeb::loadURL(""); - LLWeb::loadURL("hacker://www.google.com/"); - LLWeb::loadURL("http"); - LLWeb::loadURL("http://www.google.com/"); + LLWeb::loadURL(""); + LLWeb::loadURL("hacker://www.google.com/"); + LLWeb::loadURL("http"); + LLWeb::loadURL("http://www.google.com/"); } // @@ -8521,86 +8521,86 @@ LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p BOOL LLViewerMenuHolderGL::hideMenus() { - BOOL handled = FALSE; - - if (LLMenuHolderGL::hideMenus()) - { - handled = TRUE; - } + BOOL handled = FALSE; + + if (LLMenuHolderGL::hideMenus()) + { + handled = TRUE; + } - // drop pie menu selection - mParcelSelection = NULL; - mObjectSelection = NULL; + // drop pie menu selection + mParcelSelection = NULL; + mObjectSelection = NULL; - if (gMenuBarView) - { - gMenuBarView->clearHoverItem(); - gMenuBarView->resetMenuTrigger(); - } + if (gMenuBarView) + { + gMenuBarView->clearHoverItem(); + gMenuBarView->resetMenuTrigger(); + } - return handled; + return handled; } -void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle selection) -{ - mParcelSelection = selection; +void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle selection) +{ + mParcelSelection = selection; } -void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle selection) -{ - mObjectSelection = selection; +void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle selection) +{ + mObjectSelection = selection; } const LLRect LLViewerMenuHolderGL::getMenuRect() const { - return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); + return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); } void handle_web_browser_test(const LLSD& param) { - std::string url = param.asString(); - if (url.empty()) - { - url = "about:blank"; - } - LLWeb::loadURLInternal(url); + std::string url = param.asString(); + if (url.empty()) + { + url = "about:blank"; + } + LLWeb::loadURLInternal(url); } bool callback_clear_cache_immediately(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( option == 0 ) // YES - { - //clear cache - LLAppViewer::instance()->purgeCacheImmediate(); - } + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + //clear cache + LLAppViewer::instance()->purgeCacheImmediate(); + } - return false; + return false; } void handle_cache_clear_immediately() { - LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); + LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); } void handle_web_content_test(const LLSD& param) { - std::string url = param.asString(); - LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); + std::string url = param.asString(); + LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); } void handle_show_url(const LLSD& param) { - std::string url = param.asString(); - if (LLWeb::useExternalBrowser(url)) - { - LLWeb::loadURLExternal(url); - } - else - { - LLWeb::loadURLInternal(url); - } + std::string url = param.asString(); + if (LLWeb::useExternalBrowser(url)) + { + LLWeb::loadURLExternal(url); + } + else + { + LLWeb::loadURLInternal(url); + } } @@ -8612,378 +8612,378 @@ void handle_report_bug(const LLSD& param) void handle_buy_currency_test(void*) { - std::string url = - "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; + std::string url = + "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; - LLStringUtil::format_map_t replace; - replace["[AGENT_ID]"] = gAgent.getID().asString(); - replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); - replace["[LANGUAGE]"] = LLUI::getLanguage(); - LLStringUtil::format(url, replace); + LLStringUtil::format_map_t replace; + replace["[AGENT_ID]"] = gAgent.getID().asString(); + replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); + replace["[LANGUAGE]"] = LLUI::getLanguage(); + LLStringUtil::format(url, replace); - LL_INFOS() << "buy currency url " << url << LL_ENDL; + LL_INFOS() << "buy currency url " << url << LL_ENDL; - LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); + LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); } // SUNSHINE CLEANUP - is only the request update at the end needed now? void handle_rebake_textures(void*) { - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) return; - // Slam pending upload count to "unstick" things - bool slam_for_debug = true; - gAgentAvatarp->forceBakeAllTextures(slam_for_debug); - if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) - { - LLAppearanceMgr::instance().requestServerAppearanceUpdate(); - } + // Slam pending upload count to "unstick" things + bool slam_for_debug = true; + gAgentAvatarp->forceBakeAllTextures(slam_for_debug); + if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) + { + LLAppearanceMgr::instance().requestServerAppearanceUpdate(); + } } void toggle_visibility(void* user_data) { - LLView* viewp = (LLView*)user_data; - viewp->setVisible(!viewp->getVisible()); + LLView* viewp = (LLView*)user_data; + viewp->setVisible(!viewp->getVisible()); } BOOL get_visibility(void* user_data) { - LLView* viewp = (LLView*)user_data; - return viewp->getVisible(); + LLView* viewp = (LLView*)user_data; + return viewp->getVisible(); } class LLViewShowHoverTips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); - return true; - } + bool handleEvent(const LLSD& userdata) + { + gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); + return true; + } }; class LLViewCheckShowHoverTips : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); + return new_value; + } }; class LLViewHighlightTransparent : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; + bool handleEvent(const LLSD& userdata) + { + LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; // invisible objects skip building their render batches unless sShowDebugAlpha is true, so rebuild batches whenever toggling this flag - gPipeline.rebuildDrawInfo(); - return true; - } + gPipeline.rebuildDrawInfo(); + return true; + } }; class LLViewCheckHighlightTransparent : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; + return new_value; + } }; class LLViewBeaconWidth : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string width = userdata.asString(); - if(width == "1") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 1); - } - else if(width == "4") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 4); - } - else if(width == "16") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 16); - } - else if(width == "32") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 32); - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string width = userdata.asString(); + if(width == "1") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 1); + } + else if(width == "4") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 4); + } + else if(width == "16") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 16); + } + else if(width == "32") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 32); + } + + return true; + } }; class LLViewToggleBeacon : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - if (beacon == "scriptsbeacon") - { - LLPipeline::toggleRenderScriptedBeacons(); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) - { - LLPipeline::toggleRenderScriptedTouchBeacons(); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); - } - } - else if (beacon == "physicalbeacon") - { - LLPipeline::toggleRenderPhysicalBeacons(); - gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons() ); - } - else if (beacon == "moapbeacon") - { - LLPipeline::toggleRenderMOAPBeacons(); - gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons() ); - } - else if (beacon == "soundsbeacon") - { - LLPipeline::toggleRenderSoundBeacons(); - gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons() ); - } - else if (beacon == "particlesbeacon") - { - LLPipeline::toggleRenderParticleBeacons(); - gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons() ); - } - else if (beacon == "scripttouchbeacon") - { - LLPipeline::toggleRenderScriptedTouchBeacons(); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) - { - LLPipeline::toggleRenderScriptedBeacons(); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); - } - } - else if (beacon == "sunbeacon") - { - gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); - } - else if (beacon == "moonbeacon") - { - gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); - } - else if (beacon == "renderbeacons") - { - LLPipeline::toggleRenderBeacons(); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) - { - LLPipeline::toggleRenderHighlights(); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); - } - } - else if (beacon == "renderhighlights") - { - LLPipeline::toggleRenderHighlights(); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) - { - LLPipeline::toggleRenderBeacons(); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); - } - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + if (beacon == "scriptsbeacon") + { + LLPipeline::toggleRenderScriptedBeacons(); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) + { + LLPipeline::toggleRenderScriptedTouchBeacons(); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); + } + } + else if (beacon == "physicalbeacon") + { + LLPipeline::toggleRenderPhysicalBeacons(); + gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons() ); + } + else if (beacon == "moapbeacon") + { + LLPipeline::toggleRenderMOAPBeacons(); + gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons() ); + } + else if (beacon == "soundsbeacon") + { + LLPipeline::toggleRenderSoundBeacons(); + gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons() ); + } + else if (beacon == "particlesbeacon") + { + LLPipeline::toggleRenderParticleBeacons(); + gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons() ); + } + else if (beacon == "scripttouchbeacon") + { + LLPipeline::toggleRenderScriptedTouchBeacons(); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons() ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons() && LLPipeline::getRenderScriptedTouchBeacons()) + { + LLPipeline::toggleRenderScriptedBeacons(); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons() ); + } + } + else if (beacon == "sunbeacon") + { + gSavedSettings.setBOOL("sunbeacon", !gSavedSettings.getBOOL("sunbeacon")); + } + else if (beacon == "moonbeacon") + { + gSavedSettings.setBOOL("moonbeacon", !gSavedSettings.getBOOL("moonbeacon")); + } + else if (beacon == "renderbeacons") + { + LLPipeline::toggleRenderBeacons(); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) + { + LLPipeline::toggleRenderHighlights(); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); + } + } + else if (beacon == "renderhighlights") + { + LLPipeline::toggleRenderHighlights(); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights() ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons() && !LLPipeline::getRenderHighlights()) + { + LLPipeline::toggleRenderBeacons(); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons() ); + } + } + + return true; + } }; class LLViewCheckBeaconEnabled : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - bool new_value = false; - if (beacon == "scriptsbeacon") - { - new_value = gSavedSettings.getBOOL( "scriptsbeacon"); - LLPipeline::setRenderScriptedBeacons(new_value); - } - else if (beacon == "moapbeacon") - { - new_value = gSavedSettings.getBOOL( "moapbeacon"); - LLPipeline::setRenderMOAPBeacons(new_value); - } - else if (beacon == "physicalbeacon") - { - new_value = gSavedSettings.getBOOL( "physicalbeacon"); - LLPipeline::setRenderPhysicalBeacons(new_value); - } - else if (beacon == "soundsbeacon") - { - new_value = gSavedSettings.getBOOL( "soundsbeacon"); - LLPipeline::setRenderSoundBeacons(new_value); - } - else if (beacon == "particlesbeacon") - { - new_value = gSavedSettings.getBOOL( "particlesbeacon"); - LLPipeline::setRenderParticleBeacons(new_value); - } - else if (beacon == "scripttouchbeacon") - { - new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); - LLPipeline::setRenderScriptedTouchBeacons(new_value); - } - else if (beacon == "renderbeacons") - { - new_value = gSavedSettings.getBOOL( "renderbeacons"); - LLPipeline::setRenderBeacons(new_value); - } - else if (beacon == "renderhighlights") - { - new_value = gSavedSettings.getBOOL( "renderhighlights"); - LLPipeline::setRenderHighlights(new_value); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + bool new_value = false; + if (beacon == "scriptsbeacon") + { + new_value = gSavedSettings.getBOOL( "scriptsbeacon"); + LLPipeline::setRenderScriptedBeacons(new_value); + } + else if (beacon == "moapbeacon") + { + new_value = gSavedSettings.getBOOL( "moapbeacon"); + LLPipeline::setRenderMOAPBeacons(new_value); + } + else if (beacon == "physicalbeacon") + { + new_value = gSavedSettings.getBOOL( "physicalbeacon"); + LLPipeline::setRenderPhysicalBeacons(new_value); + } + else if (beacon == "soundsbeacon") + { + new_value = gSavedSettings.getBOOL( "soundsbeacon"); + LLPipeline::setRenderSoundBeacons(new_value); + } + else if (beacon == "particlesbeacon") + { + new_value = gSavedSettings.getBOOL( "particlesbeacon"); + LLPipeline::setRenderParticleBeacons(new_value); + } + else if (beacon == "scripttouchbeacon") + { + new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); + LLPipeline::setRenderScriptedTouchBeacons(new_value); + } + else if (beacon == "renderbeacons") + { + new_value = gSavedSettings.getBOOL( "renderbeacons"); + LLPipeline::setRenderBeacons(new_value); + } + else if (beacon == "renderhighlights") + { + new_value = gSavedSettings.getBOOL( "renderhighlights"); + LLPipeline::setRenderHighlights(new_value); + } + return new_value; + } }; class LLViewToggleRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - if (type == "hideparticles") - { - LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string type = userdata.asString(); + if (type == "hideparticles") + { + LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); + } + return true; + } }; class LLViewCheckRenderType : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - bool new_value = false; - if (type == "hideparticles") - { - new_value = LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES); - } - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + std::string type = userdata.asString(); + bool new_value = false; + if (type == "hideparticles") + { + new_value = LLPipeline::toggleRenderTypeControlNegated(LLPipeline::RENDER_TYPE_PARTICLES); + } + return new_value; + } }; class LLViewStatusAway : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.isInitialized() && gAgent.getAFK()); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.isInitialized() && gAgent.getAFK()); + } }; class LLViewStatusDoNotDisturb : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return (gAgent.isInitialized() && gAgent.isDoNotDisturb()); - } + bool handleEvent(const LLSD& userdata) + { + return (gAgent.isInitialized() && gAgent.isDoNotDisturb()); + } }; class LLViewShowHUDAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; + return true; + } }; class LLViewCheckHUDAttachments : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPipeline::sShowHUDAttachments; - return new_value; - } + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPipeline::sShowHUDAttachments; + return new_value; + } }; class LLEditEnableTakeOff : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - return LLAgentWearables::selfHasWearable(type); - return false; - } + bool handleEvent(const LLSD& userdata) + { + std::string clothing = userdata.asString(); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); + if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) + return LLAgentWearables::selfHasWearable(type); + return false; + } }; class LLEditTakeOff : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - if (clothing == "all") - LLAppearanceMgr::instance().removeAllClothesFromAvatar(); - else - { - LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE - && type < LLWearableType::WT_COUNT - && (gAgentWearables.getWearableCount(type) > 0)) - { - // MULTI-WEARABLES: assuming user wanted to remove top shirt. - U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; - LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); - LLAppearanceMgr::instance().removeItemFromAvatar(item_id); - } - - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string clothing = userdata.asString(); + if (clothing == "all") + LLAppearanceMgr::instance().removeAllClothesFromAvatar(); + else + { + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); + if (type >= LLWearableType::WT_SHAPE + && type < LLWearableType::WT_COUNT + && (gAgentWearables.getWearableCount(type) > 0)) + { + // MULTI-WEARABLES: assuming user wanted to remove top shirt. + U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; + LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); + LLAppearanceMgr::instance().removeItemFromAvatar(item_id); + } + + } + return true; + } }; class LLToolsSelectTool : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string tool_name = userdata.asString(); - if (tool_name == "focus") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); - } - else if (tool_name == "move") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); - } - else if (tool_name == "edit") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); - } - else if (tool_name == "create") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); - } - else if (tool_name == "land") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); - } - - // Note: if floater is not visible LLViewerWindow::updateLayout() will - // attempt to open it, but it won't bring it to front or de-minimize. - if (gFloaterTools && (gFloaterTools->isMinimized() || !gFloaterTools->isShown() || !gFloaterTools->isFrontmost())) - { - gFloaterTools->setMinimized(FALSE); - gFloaterTools->openFloater(); - gFloaterTools->setVisibleAndFrontmost(TRUE); - } - return true; - } + bool handleEvent(const LLSD& userdata) + { + std::string tool_name = userdata.asString(); + if (tool_name == "focus") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); + } + else if (tool_name == "move") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); + } + else if (tool_name == "edit") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); + } + else if (tool_name == "create") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); + } + else if (tool_name == "land") + { + LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); + } + + // Note: if floater is not visible LLViewerWindow::updateLayout() will + // attempt to open it, but it won't bring it to front or de-minimize. + if (gFloaterTools && (gFloaterTools->isMinimized() || !gFloaterTools->isShown() || !gFloaterTools->isFrontmost())) + { + gFloaterTools->setMinimized(FALSE); + gFloaterTools->openFloater(); + gFloaterTools->setVisibleAndFrontmost(TRUE); + } + return true; + } }; /// WINDLIGHT callbacks @@ -9002,7 +9002,7 @@ void defocusEnvFloaters() } } -bool handle_env_setting_event(std::string event_name) +bool handle_env_setting_event(std::string event_name) { if (event_name == "sunrise") { @@ -9066,126 +9066,126 @@ bool handle_env_setting_event(std::string event_name) } class LLWorldEnvSettings : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { +{ + bool handleEvent(const LLSD& userdata) + { handle_env_setting_event(userdata.asString()); - return true; - } + return true; + } }; class LLWorldEnableEnvSettings : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool result = false; - std::string event_name = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + bool result = false; + std::string event_name = userdata.asString(); if (event_name == "pause_clouds") - { + { return LLEnvironment::instance().isCloudScrollPaused(); - } + } LLSettingsSky::ptr_t sky = LLEnvironment::instance().getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL); - if (!sky) - { - return (event_name == "region"); - } + if (!sky) + { + return (event_name == "region"); + } std::string skyname = (sky) ? sky->getName() : ""; LLUUID skyid = (sky) ? sky->getAssetId() : LLUUID::null; - if (event_name == "sunrise") - { + if (event_name == "sunrise") + { result = (skyid == LLEnvironment::KNOWN_SKY_SUNRISE); - } - else if (event_name == "noon") - { + } + else if (event_name == "noon") + { result = (skyid == LLEnvironment::KNOWN_SKY_MIDDAY); - } + } else if (event_name == "legacy noon") { result = (skyid == LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY); } - else if (event_name == "sunset") - { + else if (event_name == "sunset") + { result = (skyid == LLEnvironment::KNOWN_SKY_SUNSET); - } - else if (event_name == "midnight") - { + } + else if (event_name == "midnight") + { result = (skyid == LLEnvironment::KNOWN_SKY_MIDNIGHT); - } - else if (event_name == "region") - { - return false; - } - else - { - LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; - } - return result; - } + } + else if (event_name == "region") + { + return false; + } + else + { + LL_WARNS() << "Unknown time-of-day item: " << event_name << LL_ENDL; + } + return result; + } }; class LLWorldEnvPreset : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - std::string item = userdata.asString(); + bool handleEvent(const LLSD& userdata) + { + std::string item = userdata.asString(); - if (item == "new_water") - { + if (item == "new_water") + { LLFloaterReg::showInstance("env_fixed_environmentent_water", "new"); - } - else if (item == "edit_water") - { + } + else if (item == "edit_water") + { LLFloaterReg::showInstance("env_fixed_environmentent_water", "edit"); - } - else if (item == "new_sky") - { + } + else if (item == "new_sky") + { LLFloaterReg::showInstance("env_fixed_environmentent_sky", "new"); - } - else if (item == "edit_sky") - { + } + else if (item == "edit_sky") + { LLFloaterReg::showInstance("env_fixed_environmentent_sky", "edit"); - } - else if (item == "new_day_cycle") - { + } + else if (item == "new_day_cycle") + { LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); - } - else if (item == "edit_day_cycle") - { - LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); - } - else - { - LL_WARNS() << "Unknown item selected" << LL_ENDL; - } + } + else if (item == "edit_day_cycle") + { + LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("edit_context", "inventory")); + } + else + { + LL_WARNS() << "Unknown item selected" << LL_ENDL; + } - return true; - } + return true; + } }; class LLWorldEnableEnvPreset : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { - return false; - } + return false; + } }; /// Post-Process callbacks class LLWorldPostProcess : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_post_process"); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("env_post_process"); + return true; + } }; class LLWorldCheckBanLines : public view_listener_t @@ -9209,684 +9209,684 @@ class LLWorldShowBanLines : public view_listener_t void handle_flush_name_caches() { - if (gCacheName) gCacheName->clear(); + if (gCacheName) gCacheName->clear(); } class LLUploadCostCalculator : public view_listener_t { - std::string mCostStr; - - bool handleEvent(const LLSD& userdata) - { - std::vector fields; - std::string str = userdata.asString(); - boost::split(fields, str, boost::is_any_of(",")); - if (fields.size()<1) - { - return false; - } - std::string menu_name = fields[0]; - std::string asset_type_str = "texture"; - if (fields.size()>1) - { - asset_type_str = fields[1]; - } - LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; - calculateCost(asset_type_str); - gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); - - return true; - } - - void calculateCost(const std::string& asset_type_str); + std::string mCostStr; + + bool handleEvent(const LLSD& userdata) + { + std::vector fields; + std::string str = userdata.asString(); + boost::split(fields, str, boost::is_any_of(",")); + if (fields.size()<1) + { + return false; + } + std::string menu_name = fields[0]; + std::string asset_type_str = "texture"; + if (fields.size()>1) + { + asset_type_str = fields[1]; + } + LL_DEBUGS("Benefits") << "userdata " << userdata << " menu_name " << menu_name << " asset_type_str " << asset_type_str << LL_ENDL; + calculateCost(asset_type_str); + gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); + + return true; + } + + void calculateCost(const std::string& asset_type_str); public: - LLUploadCostCalculator() - { - } + LLUploadCostCalculator() + { + } }; class LLUpdateMembershipLabel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); - gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); + bool handleEvent(const LLSD& userdata) + { + const std::string label_str = LLAgentBenefitsMgr::isCurrent("Base") ? LLTrans::getString("MembershipUpgradeText") : LLTrans::getString("MembershipPremiumText"); + gMenuHolder->childSetLabelArg("Membership", "[Membership]", label_str); - return true; - } + return true; + } }; void handle_voice_morphing_subscribe() { - LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); + LLWeb::loadURL(LLTrans::getString("voice_morphing_url")); } void handle_premium_voice_morphing_subscribe() { - LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); + LLWeb::loadURL(LLTrans::getString("premium_voice_morphing_url")); } class LLToggleUIHints : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); - // toggle - ui_hints_enabled = !ui_hints_enabled; - gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); - return true; - } + bool handleEvent(const LLSD& userdata) + { + bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); + // toggle + ui_hints_enabled = !ui_hints_enabled; + gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); + return true; + } }; void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str) { - S32 upload_cost = -1; - - if (asset_type_str == "texture") - { - upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - } - else if (asset_type_str == "animation") - { - upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); - } - else if (asset_type_str == "sound") - { - upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); - } - if (upload_cost < 0) - { - LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; - } - mCostStr = std::to_string(upload_cost); + S32 upload_cost = -1; + + if (asset_type_str == "texture") + { + upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); + } + else if (asset_type_str == "animation") + { + upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); + } + else if (asset_type_str == "sound") + { + upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); + } + if (upload_cost < 0) + { + LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; + } + mCostStr = std::to_string(upload_cost); } void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) { - static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_hide_navbar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } - show_navbar_context_menu->buildDrawLabels(); - show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); + static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_hide_navbar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } + show_navbar_context_menu->buildDrawLabels(); + show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); } void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y) { - static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_topinfobar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_topinfobar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild("Landmark"); - if (!LLLandmarkActions::landmarkAlreadyExists()) - { - landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); - } - else - { - landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); - } + LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild("Landmark"); + if (!LLLandmarkActions::landmarkAlreadyExists()) + { + landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); + } + else + { + landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); + } - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } - show_topbarinfo_context_menu->buildDrawLabels(); - show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); + show_topbarinfo_context_menu->buildDrawLabels(); + show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); } void initialize_edit_menu() { - view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); - view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); - view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); - view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); - view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); - view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); - view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); - view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); - view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); - view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); - view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); - view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); - view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); - view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); - view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); - view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); - view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); + view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); + view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); + view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); + view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); + view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); + view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); + view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); + view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); + view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); + view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); + view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); + view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); + view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); + view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); + view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); + view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); + view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); } void initialize_spellcheck_menu() { - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); - enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); - commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); - enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); - commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); - enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); + commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); + commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); + commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); } void initialize_menus() { - // A parameterized event handler used as ctrl-8/9/0 zoom controls below. - class LLZoomer : public view_listener_t - { - public: - // The "mult" parameter says whether "val" is a multiplier or used to set the value. - LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(const LLSD& userdata) - { - F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; - LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); - gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. - return true; - } - private: - F32 mVal; - bool mMult; - }; - - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - - // Generic enable and visible - // 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"); - - view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); - - enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); - - // Agent - commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); - enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); - commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); - commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); - commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); - enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); - enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); - - // File menu - init_menu_file(); - - view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); - view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); - view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); - view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); - view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); - commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); + // A parameterized event handler used as ctrl-8/9/0 zoom controls below. + class LLZoomer : public view_listener_t + { + public: + // The "mult" parameter says whether "val" is a multiplier or used to set the value. + LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} + bool handleEvent(const LLSD& userdata) + { + F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; + LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); + gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. + return true; + } + private: + F32 mVal; + bool mMult; + }; + + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // Generic enable and visible + // 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"); + + view_listener_t::addEnable(new LLUpdateMembershipLabel(), "Membership.UpdateLabel"); + + enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed)); + + // Agent + commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); + enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land)); + commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2)); + commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2)); + commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); + enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); + enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); + + // File menu + init_menu_file(); + + view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); + view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); + view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); + view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight"); + view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); + commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); commit.add("NowWearing", boost::bind(&handle_now_wearing)); - commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); - commit.add("EditShape", boost::bind(&handle_edit_shape)); - commit.add("HoverHeight", boost::bind(&handle_hover_height)); - commit.add("EditPhysics", boost::bind(&handle_edit_physics)); - - // View menu - view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); - view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); - view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); - view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); - view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); - view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); - view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); - view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); - view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); - view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); - view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); - view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); - view_listener_t::addMenu(new LLViewToggleUI(), "View.ToggleUI"); - - view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); - view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); - view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); - - view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); - view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); - view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); - view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); - view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway"); - view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); - view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); - - //Communicate Nearby chat - view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); - - // Communicate > Voice morphing > Subscribe... - commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); - // Communicate > Voice morphing > Premium perk... - commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); - LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); - enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" - , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); - commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" - , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); - - // World menu - view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); - view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); - view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); - view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); - view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); - view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); - view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); - view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); - - view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); - view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); - view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); - view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); - - view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); - - view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); - view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); - view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); - view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); - view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); + commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); + commit.add("EditShape", boost::bind(&handle_edit_shape)); + commit.add("HoverHeight", boost::bind(&handle_hover_height)); + commit.add("EditPhysics", boost::bind(&handle_edit_physics)); + + // View menu + view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); + view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); + view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); + view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); + view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); + view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); + view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); + view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); + view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); + view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); + view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); + view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); + view_listener_t::addMenu(new LLViewToggleUI(), "View.ToggleUI"); + + view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); + view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); + view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); + + view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); + view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); + view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); + view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); + view_listener_t::addMenu(new LLViewStatusAway(), "View.Status.CheckAway"); + view_listener_t::addMenu(new LLViewStatusDoNotDisturb(), "View.Status.CheckDoNotDisturb"); + view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); + + //Communicate Nearby chat + view_listener_t::addMenu(new LLCommunicateNearbyChat(), "Communicate.NearbyChat"); + + // Communicate > Voice morphing > Subscribe... + commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe)); + // Communicate > Voice morphing > Premium perk... + commit.add("Communicate.VoiceMorphing.PremiumPerk", boost::bind(&handle_premium_voice_morphing_subscribe)); + LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance(); + enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check" + , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing")); + commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click" + , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing")); + + // World menu + view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); + view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); + view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); + view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); + view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); + view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); + view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); + view_listener_t::addMenu(new LLWorldLindenHome(), "World.LindenHome"); + + view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); + view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); + view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); + view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); + + view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); + + view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); + view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings"); + view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); + view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); + view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines"); view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines"); - // Tools menu - view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); - view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); - view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); + // Tools menu + view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); + view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); + view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); view_listener_t::addMenu(new LLToolsSelectInvisibleObjects(), "Tools.SelectInvisibleObjects"); view_listener_t::addMenu(new LLToolsSelectReflectionProbes(), "Tools.SelectReflectionProbes"); - view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); - view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); - view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); - view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); - view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); - view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); - view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); - commit.add("Tools.Link", boost::bind(&handle_link_objects)); - commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); - view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); - view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); - view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); - view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); - - view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); - view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); - enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); - enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); - enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); - enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); - enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); - view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); - - view_listener_t::addMenu(new LLToolsEnablePathfinding(), "Tools.EnablePathfinding"); - view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView"); - view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion"); - view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion"); - - // Help menu - // most items use the ShowFloater method - view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); - - // Advanced menu - view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); - view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); - view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); - - // Advanced > HUD Info - view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); - view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); - - // Advanced Other Settings - view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); - - // Advanced > Render > Types - view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); - view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); - - //// Advanced > Render > Features - view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); - view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); - - view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity"); - view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity"); - - // Advanced > Render > Info Displays - view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); - commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); - view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); - view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); - // Develop > Render - view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); - view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); - view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); - view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); - - #ifdef TOGGLE_HACKED_GODLIKE_VIEWER - view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); - #endif - - // Advanced > World - view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); - view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); + view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); + view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); + view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); + view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); + view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); + view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); + view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart"); + commit.add("Tools.Link", boost::bind(&handle_link_objects)); + commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); + view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); + view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); + commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); + commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); + commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); + view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); + view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); + + view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); + view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); + enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); + enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); + enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); + enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); + enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); + view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); + + view_listener_t::addMenu(new LLToolsEnablePathfinding(), "Tools.EnablePathfinding"); + view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView"); + view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion"); + view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion"); + + // Help menu + // most items use the ShowFloater method + view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); + + // Advanced menu + view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); + view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); + view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); + + // Advanced > HUD Info + view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); + view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); + + // Advanced Other Settings + view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); + + // Advanced > Render > Types + view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); + view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); + + //// Advanced > Render > Features + view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); + view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); + + view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity"); + view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity"); + + // Advanced > Render > Info Displays + view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); + commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info)); + view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); + view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); + // Develop > Render + view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); + view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); + view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); + view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); + view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); + view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); + + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER + view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); + #endif + + // Advanced > World + view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); + view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); view_listener_t::addMenu(new LLAdvancedToggleStatsRecorder(), "Advanced.ToggleStatsRecorder"); view_listener_t::addMenu(new LLAdvancedCheckStatsRecorder(), "Advanced.CheckStatsRecorder"); view_listener_t::addMenu(new LLAdvancedToggleInterestList360Mode(), "Advanced.ToggleInterestList360Mode"); view_listener_t::addMenu(new LLAdvancedCheckInterestList360Mode(), "Advanced.CheckInterestList360Mode"); view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); - // Advanced > UI - commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser - commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater - commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); - commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); - view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); - view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); - view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); - commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); - view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); - view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); - view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); - view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); - view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); - view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); - view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); - view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); - view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); - view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); - - // Advanced > XUI - commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); - view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); - view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); - view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); - - // Advanced > Character > Grab Baked Texture - view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); - view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); - - // Advanced > Character > Character Tests - view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); - - view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); - view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); - - // Advanced > Character > Animation Speed - view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); - view_listener_t::addMenu(new LLAdvancedAnimTenSlower(), "Advanced.AnimTenSlower"); - view_listener_t::addMenu(new LLAdvancedAnimResetAll(), "Advanced.AnimResetAll"); - - // Advanced > Character (toplevel) - view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); - view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); - view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); - view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); - view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); - view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); - view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); - view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); - view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); - // Advanced > Network - view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); + // Advanced > UI + commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser + commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater + commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2)); + commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2)); + view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); + view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); + view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); + commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); + commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); + view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); + view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); + view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); + view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); + view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); + view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); + view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); + view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); + + // Advanced > XUI + commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); + view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); + view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); + view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); + commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); + + // Advanced > Character > Grab Baked Texture + view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); + view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); + + // Advanced > Character > Character Tests + view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); + + view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); + view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); + + // Advanced > Character > Animation Speed + view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); + view_listener_t::addMenu(new LLAdvancedAnimTenSlower(), "Advanced.AnimTenSlower"); + view_listener_t::addMenu(new LLAdvancedAnimResetAll(), "Advanced.AnimResetAll"); + + // Advanced > Character (toplevel) + view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); + view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); + view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); + view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); + view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); + view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); + view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); + view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); + view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); + // Advanced > Network + view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); // Advanced > Cache view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache"); - // Advanced > Recorder - 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 > Recorder + 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_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); + // Advanced > Debugging + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); + view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); - // Advanced (toplevel) - view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); + // Advanced (toplevel) + view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest"); - view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); - view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); - - view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); - view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); - - // Develop >Set logging level - view_listener_t::addMenu(new LLDevelopCheckLoggingLevel(), "Develop.CheckLoggingLevel"); - view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); - - //Develop (clear cache immediately) - commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); - - // Develop (Fonts debugging) - commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); - commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); - - // Admin >Object - view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); - view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); - view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); - view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); - - // Admin >Parcel - view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); - view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); - view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); - - // Admin >Region - view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); - // Admin top level - view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); - - // Self context menu - view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); - enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); - view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); - - view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); - - // we don't use boost::bind directly to delay side tray construction - view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); - view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab"); - - // Avatar pie menu - view_listener_t::addMenu(new LLAvatarCheckImpostorMode(), "Avatar.CheckImpostorMode"); - view_listener_t::addMenu(new LLAvatarSetImpostorMode(), "Avatar.SetImpostorMode"); - view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); - view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); - view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); - commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); - view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); - view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); - view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); - commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); - view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); - view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); - enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); - view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); - view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); - view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); - view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); - view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); - view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); - view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); - view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); - enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); + view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); + view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); + + view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); + view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); + + // Develop >Set logging level + view_listener_t::addMenu(new LLDevelopCheckLoggingLevel(), "Develop.CheckLoggingLevel"); + view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel"); + + //Develop (clear cache immediately) + commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + + // Develop (Fonts debugging) + commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); + commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); + + // Admin >Object + view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); + view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); + view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); + view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); + + // Admin >Parcel + view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); + view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); + view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); + + // Admin >Region + view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); + // Admin top level + view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); + + // Self context menu + view_listener_t::addMenu(new LLSelfToggleSitStand(), "Self.ToggleSitStand"); + enable.add("Self.EnableSitStand", boost::bind(&enable_sit_stand)); + view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); + + view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); + + // we don't use boost::bind directly to delay side tray construction + view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); + view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab"); + + // Avatar pie menu + view_listener_t::addMenu(new LLAvatarCheckImpostorMode(), "Avatar.CheckImpostorMode"); + view_listener_t::addMenu(new LLAvatarSetImpostorMode(), "Avatar.SetImpostorMode"); + view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); + view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); + view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); + commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); + view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); + view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); + view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); + commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); + commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); + view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); + view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); + enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); + view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); + view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); + view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); + view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); + view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); + view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); + view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); + enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible)); - commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); - - view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); - enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); - - // Object pie menu - view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); - commit.add("Object.Touch", boost::bind(&handle_object_touch)); - commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); - commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - commit.add("Object.Delete", boost::bind(&handle_object_delete)); - view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); - view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); - view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); - commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); - view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); - - enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); - enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - - commit.add("Object.Buy", boost::bind(&handle_buy)); - commit.add("Object.Edit", boost::bind(&handle_object_edit)); + commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); + + view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); + enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); + + // Object pie menu + view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); + commit.add("Object.Touch", boost::bind(&handle_object_touch)); + commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); + commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); + commit.add("Object.Delete", boost::bind(&handle_object_delete)); + view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); + view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); + view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); + commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); + view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); + + enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); + enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); + + commit.add("Object.Buy", boost::bind(&handle_buy)); + commit.add("Object.Edit", boost::bind(&handle_object_edit)); commit.add("Object.Edit", boost::bind(&handle_object_edit)); commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); - commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); - commit.add("Object.Open", boost::bind(&handle_object_open)); - commit.add("Object.Take", boost::bind(&handle_take)); - commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); + commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); + commit.add("Object.Open", boost::bind(&handle_object_open)); + commit.add("Object.Take", boost::bind(&handle_take)); + commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect)); enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); - enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); - enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); - enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); - enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); - - enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); - enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); - - view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); - enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); - - enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); - enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); - commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); - - // Attachment pie menu - enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); - view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); - view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); - view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); - view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); - view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); - view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); - - // Land pie menu - view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); - view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); + enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); + enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); + enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); + enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); + + enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); + enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); + + view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); + enable.add("Object.EnableDuplicate", boost::bind(&LLSelectMgr::canDuplicate, LLSelectMgr::getInstance())); + view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); + + enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); + enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); + enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute)); + enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); + commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); + + // Attachment pie menu + enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); + view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); + view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); + view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); + view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); + view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); + view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); + + // Land pie menu + view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); + view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); view_listener_t::addMenu(new LLLandCanSit(), "Land.CanSit"); - view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); - view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); - - // Particle muting - view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); - - view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - commit.add("Land.Buy", boost::bind(&handle_buy_land)); - - // Generic actions - commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); - commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); - view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); - view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); - view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); - view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); - view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); + view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); + view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); + + // Particle muting + view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute"); + + view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); + commit.add("Land.Buy", boost::bind(&handle_buy_land)); + + // Generic actions + commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); + commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); + view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); + view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); + view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); + view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); + view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks"); - view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); - view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); + view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); + view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); - view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); - view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); - commit.add("PayObject", boost::bind(&handle_give_money_dialog)); - - commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); - - enable.add("EnablePayObject", boost::bind(&enable_pay_object)); - enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); - enable.add("EnableEdit", boost::bind(&enable_object_edit)); - enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); - enable.add("VisibleBuild", boost::bind(&enable_object_build)); - commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); - enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); - enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); - commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); - enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); + view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); + view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); + commit.add("PayObject", boost::bind(&handle_give_money_dialog)); + + commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow)); + + enable.add("EnablePayObject", boost::bind(&enable_pay_object)); + enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); + enable.add("EnableEdit", boost::bind(&enable_object_edit)); + enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle)); + enable.add("VisibleBuild", boost::bind(&enable_object_build)); + commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects)); + enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets)); + enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets)); + commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); + enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); - view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); - view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); - view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); - view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); - view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); - view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); - view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); - view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); + view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); + view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); + view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); + view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); + view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); + view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); + view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); + view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b43de3fe3f..6ac783fec5 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenu.h * @brief Builds menus out of objects * * $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$ */ @@ -156,38 +156,38 @@ U64 info_display_from_string(std::string info_display); class LLViewerMenuHolderGL : public LLMenuHolderGL { public: - struct Params : public LLInitParam::Block - {}; + struct Params : public LLInitParam::Block + {}; + + LLViewerMenuHolderGL(const Params& p); - LLViewerMenuHolderGL(const Params& p); + virtual BOOL hideMenus(); - virtual BOOL hideMenus(); - - void setParcelSelection(LLSafeHandle selection); - void setObjectSelection(LLSafeHandle selection); + void setParcelSelection(LLSafeHandle selection); + void setObjectSelection(LLSafeHandle selection); - virtual const LLRect getMenuRect() const; + virtual const LLRect getMenuRect() const; protected: - LLSafeHandle mParcelSelection; - LLSafeHandle mObjectSelection; + LLSafeHandle mParcelSelection; + LLSafeHandle mObjectSelection; }; -extern LLMenuBarGL* gMenuBarView; -//extern LLView* gMenuBarHolder; -extern LLMenuGL* gEditMenu; -extern LLMenuGL* gPopupMenuView; -extern LLViewerMenuHolderGL* gMenuHolder; -extern LLMenuBarGL* gLoginMenuBarView; +extern LLMenuBarGL* gMenuBarView; +//extern LLView* gMenuBarHolder; +extern LLMenuGL* gEditMenu; +extern LLMenuGL* gPopupMenuView; +extern LLViewerMenuHolderGL* gMenuHolder; +extern LLMenuBarGL* gLoginMenuBarView; // Context menus in 3D scene -extern LLContextMenu *gMenuAvatarSelf; -extern LLContextMenu *gMenuAvatarOther; -extern LLContextMenu *gMenuObject; -extern LLContextMenu *gMenuAttachmentSelf; -extern LLContextMenu *gMenuAttachmentOther; -extern LLContextMenu *gMenuLand; -extern LLContextMenu *gMenuMuteParticle; +extern LLContextMenu *gMenuAvatarSelf; +extern LLContextMenu *gMenuAvatarOther; +extern LLContextMenu *gMenuObject; +extern LLContextMenu *gMenuAttachmentSelf; +extern LLContextMenu *gMenuAttachmentOther; +extern LLContextMenu *gMenuLand; +extern LLContextMenu *gMenuMuteParticle; // Needed to build menus when attachment site list available extern LLMenuGL* gAttachSubMenu; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a1dc7119ce..243c3aeff8 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenufile.cpp * @brief "File" menu in the main menu bar. * * $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$ */ @@ -47,17 +47,17 @@ #include "llimagej2c.h" #include "llimagejpeg.h" #include "llimagetga.h" -#include "llinventorymodel.h" // gInventory +#include "llinventorymodel.h" // gInventory #include "llpluginclassmedia.h" #include "llresourcedata.h" #include "llstatusbar.h" #include "lltinygltfhelper.h" #include "lltoast.h" -#include "llviewercontrol.h" // gSavedSettings +#include "llviewercontrol.h" // gSavedSettings #include "llviewertexturelist.h" #include "lluictrlfactory.h" #include "llviewerinventory.h" -#include "llviewermenu.h" // gMenuHolder +#include "llviewermenu.h" // gMenuHolder #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" @@ -83,24 +83,24 @@ class LLFileEnableUpload : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { return true; - } + } }; class LLFileEnableUploadModel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model"); - if (fmp && fmp->isModelLoading()) - { - return false; - } - - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::findInstance("upload_model"); + if (fmp && fmp->isModelLoading()) + { + return false; + } + + return true; + } }; class LLFileEnableUploadMaterial : public view_listener_t @@ -118,18 +118,18 @@ class LLFileEnableUploadMaterial : public view_listener_t class LLMeshEnabled : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gSavedSettings.getBOOL("MeshEnabled"); - } + bool handleEvent(const LLSD& userdata) + { + return gSavedSettings.getBOOL("MeshEnabled"); + } }; class LLMeshUploadVisible : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - return gMeshRepo.meshUploadEnabled(); - } + bool handleEvent(const LLSD& userdata) + { + return gMeshRepo.meshUploadEnabled(); + } }; LLMutex* LLFilePickerThread::sMutex = NULL; @@ -139,51 +139,51 @@ void LLFilePickerThread::getFile() { #if LL_WINDOWS // Todo: get rid of LLFilePickerThread and make this modeless - start(); + start(); #elif LL_DARWIN runModeless(); #else - run(); + run(); #endif } -//virtual +//virtual void LLFilePickerThread::run() { #if LL_WINDOWS - bool blocking = false; + bool blocking = false; #else - bool blocking = true; // modal + bool blocking = true; // modal #endif - LLFilePicker picker; - - if (mIsSaveDialog) - { - if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) - { - mResponses.push_back(picker.getFirstFile()); - } - } - else - { - bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking); - if (result) - { - std::string filename = picker.getFirstFile(); // consider copying mFiles directly - do - { - mResponses.push_back(filename); - filename = picker.getNextFile(); - } - while (mIsGetMultiple && !filename.empty()); - } - } - - { - LLMutexLock lock(sMutex); - sDeadQ.push(this); - } + LLFilePicker picker; + + if (mIsSaveDialog) + { + if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) + { + mResponses.push_back(picker.getFirstFile()); + } + } + else + { + bool result = mIsGetMultiple ? picker.getMultipleOpenFiles(mLoadFilter, blocking) : picker.getOpenFile(mLoadFilter, blocking); + if (result) + { + std::string filename = picker.getFirstFile(); // consider copying mFiles directly + do + { + mResponses.push_back(filename); + filename = picker.getNextFile(); + } + while (mIsGetMultiple && !filename.empty()); + } + } + + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } } void LLFilePickerThread::runModeless() @@ -206,7 +206,7 @@ void LLFilePickerThread::runModeless() { result = picker.getOpenFileModeless(mLoadFilter, modelessVectorCallback, this); } - + if (!result) { LLMutexLock lock(sMutex); @@ -223,7 +223,7 @@ void LLFilePickerThread::modelessStringCallback(bool success, { picker->mResponses.push_back(response); } - + { LLMutexLock lock(sMutex); sDeadQ.push(picker); @@ -255,7 +255,7 @@ void LLFilePickerThread::modelessVectorCallback(bool success, } } } - + { LLMutexLock lock(sMutex); sDeadQ.push(picker); @@ -265,66 +265,66 @@ void LLFilePickerThread::modelessVectorCallback(bool success, //static void LLFilePickerThread::initClass() { - sMutex = new LLMutex(); + sMutex = new LLMutex(); } //static void LLFilePickerThread::cleanupClass() { - clearDead(); - - delete sMutex; - sMutex = NULL; + clearDead(); + + delete sMutex; + sMutex = NULL; } //static void LLFilePickerThread::clearDead() { - if (!sDeadQ.empty()) - { - LLMutexLock lock(sMutex); - while (!sDeadQ.empty()) - { - LLFilePickerThread* thread = sDeadQ.front(); - thread->notify(thread->mResponses); - delete thread; - sDeadQ.pop(); - } - } + if (!sDeadQ.empty()) + { + LLMutexLock lock(sMutex); + while (!sDeadQ.empty()) + { + LLFilePickerThread* thread = sDeadQ.front(); + thread->notify(thread->mResponses); + delete thread; + sDeadQ.pop(); + } + } } LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb) - : LLFilePickerThread(filter, get_multiple), - mLoadFilter(filter), - mSaveFilter(LLFilePicker::FFSAVE_ALL), - mFilePickedSignal(NULL), - mFailureSignal(NULL) + : LLFilePickerThread(filter, get_multiple), + mLoadFilter(filter), + mSaveFilter(LLFilePicker::FFSAVE_ALL), + mFilePickedSignal(NULL), + mFailureSignal(NULL) { - mFilePickedSignal = new file_picked_signal_t(); - mFilePickedSignal->connect(cb); + mFilePickedSignal = new file_picked_signal_t(); + mFilePickedSignal->connect(cb); - mFailureSignal = new file_picked_signal_t(); - mFailureSignal->connect(failure_cb); + mFailureSignal = new file_picked_signal_t(); + mFailureSignal->connect(failure_cb); } LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb) - : LLFilePickerThread(filter, proposed_name), - mLoadFilter(LLFilePicker::FFLOAD_ALL), - mSaveFilter(filter), - mFilePickedSignal(NULL), - mFailureSignal(NULL) + : LLFilePickerThread(filter, proposed_name), + mLoadFilter(LLFilePicker::FFLOAD_ALL), + mSaveFilter(filter), + mFilePickedSignal(NULL), + mFailureSignal(NULL) { - mFilePickedSignal = new file_picked_signal_t(); - mFilePickedSignal->connect(cb); + mFilePickedSignal = new file_picked_signal_t(); + mFilePickedSignal->connect(cb); - mFailureSignal = new file_picked_signal_t(); - mFailureSignal->connect(failure_cb); + mFailureSignal = new file_picked_signal_t(); + mFailureSignal->connect(failure_cb); } LLFilePickerReplyThread::~LLFilePickerReplyThread() { - delete mFilePickedSignal; - delete mFailureSignal; + delete mFilePickedSignal; + delete mFailureSignal; } void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb) @@ -339,20 +339,20 @@ void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type void LLFilePickerReplyThread::notify(const std::vector& filenames) { - if (filenames.empty()) - { - if (mFailureSignal) - { - (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); - } - } - else - { - if (mFilePickedSignal) - { - (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); - } - } + if (filenames.empty()) + { + if (mFailureSignal) + { + (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); + } + } + else + { + if (mFilePickedSignal) + { + (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); + } + } } @@ -389,167 +389,167 @@ static std::string MATERIAL_EXTENSIONS = "gltf glb"; std::string build_extensions_string(LLFilePicker::ELoadFilter filter) { - switch(filter) - { + switch(filter) + { #if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: - return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: - return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: - return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: - return SLOBJECT_EXTENSIONS; - case LLFilePicker::FFLOAD_MODEL: - return MODEL_EXTENSIONS; + case LLFilePicker::FFLOAD_IMAGE: + return IMAGE_EXTENSIONS; + case LLFilePicker::FFLOAD_WAV: + return SOUND_EXTENSIONS; + case LLFilePicker::FFLOAD_ANIM: + return ANIM_EXTENSIONS; + case LLFilePicker::FFLOAD_SLOBJECT: + return SLOBJECT_EXTENSIONS; + case LLFilePicker::FFLOAD_MODEL: + return MODEL_EXTENSIONS; case LLFilePicker::FFLOAD_MATERIAL: return MATERIAL_EXTENSIONS; - case LLFilePicker::FFLOAD_XML: - return XML_EXTENSIONS; + case LLFilePicker::FFLOAD_XML: + return XML_EXTENSIONS; case LLFilePicker::FFLOAD_ALL: case LLFilePicker::FFLOAD_EXE: - return ALL_FILE_EXTENSIONS; + return ALL_FILE_EXTENSIONS; #endif default: - return ALL_FILE_EXTENSIONS; - } + return ALL_FILE_EXTENSIONS; + } } const bool check_file_extension(const std::string& filename, LLFilePicker::ELoadFilter type) { - std::string ext = gDirUtilp->getExtension(filename); - - //strincmp doesn't like NULL pointers - if (ext.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - LLSD args; - args["FILE"] = short_name; - LLNotificationsUtil::add("NoFileExtension", args); - return false; - } - else - { - //so there is an extension - //loop over the valid extensions and compare to see - //if the extension is valid - - //now grab the set of valid file extensions - std::string valid_extensions = build_extensions_string(type); - - BOOL ext_valid = FALSE; - - typedef boost::tokenizer > tokenizer; - boost::char_separator sep(" "); - tokenizer tokens(valid_extensions, sep); - tokenizer::iterator token_iter; - - //now loop over all valid file extensions - //and compare them to the extension of the file - //to be uploaded - for (token_iter = tokens.begin(); - token_iter != tokens.end() && ext_valid != TRUE; - ++token_iter) - { - const std::string& cur_token = *token_iter; - - if (cur_token == ext || cur_token == "*.*") - { - //valid extension - //or the acceptable extension is any - ext_valid = TRUE; - } - }//end for (loop over all tokens) - - if (ext_valid == FALSE) - { - //should only get here if the extension exists - //but is invalid - LLSD args; - args["EXTENSION"] = ext; - args["VALIDS"] = valid_extensions; - LLNotificationsUtil::add("InvalidFileExtension", args); - return false; - } - }//end else (non-null extension) - return true; + std::string ext = gDirUtilp->getExtension(filename); + + //strincmp doesn't like NULL pointers + if (ext.empty()) + { + std::string short_name = gDirUtilp->getBaseFileName(filename); + + // No extension + LLSD args; + args["FILE"] = short_name; + LLNotificationsUtil::add("NoFileExtension", args); + return false; + } + else + { + //so there is an extension + //loop over the valid extensions and compare to see + //if the extension is valid + + //now grab the set of valid file extensions + std::string valid_extensions = build_extensions_string(type); + + BOOL ext_valid = FALSE; + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep(" "); + tokenizer tokens(valid_extensions, sep); + tokenizer::iterator token_iter; + + //now loop over all valid file extensions + //and compare them to the extension of the file + //to be uploaded + for (token_iter = tokens.begin(); + token_iter != tokens.end() && ext_valid != TRUE; + ++token_iter) + { + const std::string& cur_token = *token_iter; + + if (cur_token == ext || cur_token == "*.*") + { + //valid extension + //or the acceptable extension is any + ext_valid = TRUE; + } + }//end for (loop over all tokens) + + if (ext_valid == FALSE) + { + //should only get here if the extension exists + //but is invalid + LLSD args; + args["EXTENSION"] = ext; + args["VALIDS"] = valid_extensions; + LLNotificationsUtil::add("InvalidFileExtension", args); + return false; + } + }//end else (non-null extension) + return true; } const void upload_single_file(const std::vector& filenames, LLFilePicker::ELoadFilter type) { - std::string filename = filenames[0]; - if (!check_file_extension(filename, type)) return; - - if (!filename.empty()) - { - if (type == LLFilePicker::FFLOAD_WAV) - { - // pre-qualify wavs to make sure the format is acceptable - std::string error_msg; - if (check_for_invalid_wav_formats(filename, error_msg)) - { - LL_INFOS() << error_msg << ": " << filename << LL_ENDL; - LLSD args; - args["FILE"] = filename; - LLNotificationsUtil::add(error_msg, args); - return; - } - else - { - LLFloaterReg::showInstance("upload_sound", LLSD(filename)); - } - } - if (type == LLFilePicker::FFLOAD_IMAGE) - { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); - } - if (type == LLFilePicker::FFLOAD_ANIM) - { - std::string filename_lc(filename); - LLStringUtil::toLower(filename_lc); - if (filename_lc.rfind(".anim") != std::string::npos) - { - LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); - } - else - { - LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); - } - } - } - return; + std::string filename = filenames[0]; + if (!check_file_extension(filename, type)) return; + + if (!filename.empty()) + { + if (type == LLFilePicker::FFLOAD_WAV) + { + // pre-qualify wavs to make sure the format is acceptable + std::string error_msg; + if (check_for_invalid_wav_formats(filename, error_msg)) + { + LL_INFOS() << error_msg << ": " << filename << LL_ENDL; + LLSD args; + args["FILE"] = filename; + LLNotificationsUtil::add(error_msg, args); + return; + } + else + { + LLFloaterReg::showInstance("upload_sound", LLSD(filename)); + } + } + if (type == LLFilePicker::FFLOAD_IMAGE) + { + LLFloaterReg::showInstance("upload_image", LLSD(filename)); + } + if (type == LLFilePicker::FFLOAD_ANIM) + { + std::string filename_lc(filename); + LLStringUtil::toLower(filename_lc); + if (filename_lc.rfind(".anim") != std::string::npos) + { + LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); + } + else + { + LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); + } + } + } + return; } void do_bulk_upload(std::vector filenames, const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) - { - // Cancel upload - return; - } - - for (std::vector::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - std::string filename = (*in_iter); - - std::string name = gDirUtilp->getBaseFileName(filename, true); - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII(asset_name, '?'); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string ext = gDirUtilp->getExtension(filename); - LLAssetType::EType asset_type; - U32 codec; - S32 expected_upload_cost; - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) - { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + // Cancel upload + return; + } + + for (std::vector::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + + std::string name = gDirUtilp->getBaseFileName(filename, true); + std::string asset_name = name; + LLStringUtil::replaceNonstandardASCII(asset_name, '?'); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string ext = gDirUtilp->getExtension(filename); + LLAssetType::EType asset_type; + U32 codec; + S32 expected_upload_cost; + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) + { LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( filename, asset_name, @@ -585,34 +585,34 @@ void do_bulk_upload(std::vector filenames, const LLSD& notification bool get_bulk_upload_expected_cost(const std::vector& filenames, S32& total_cost, S32& file_count, S32& bvh_count) { - total_cost = 0; - file_count = 0; - bvh_count = 0; - for (std::vector::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - std::string filename = (*in_iter); - std::string ext = gDirUtilp->getExtension(filename); - - if (ext == "bvh") - { - bvh_count++; - } - - LLAssetType::EType asset_type; - U32 codec; - S32 cost; - - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) - { - total_cost += cost; - file_count++; - } + total_cost = 0; + file_count = 0; + bvh_count = 0; + for (std::vector::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + std::string filename = (*in_iter); + std::string ext = gDirUtilp->getExtension(filename); + + if (ext == "bvh") + { + bvh_count++; + } + + LLAssetType::EType asset_type; + U32 codec; + S32 cost; + + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && + LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) + { + total_cost += cost; + file_count++; + } if (ext == "gltf" || ext == "glb") { S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - + tinygltf::Model model; if (LLTinyGLTFHelper::loadModel(filename, model)) @@ -652,87 +652,87 @@ bool get_bulk_upload_expected_cost(const std::vector& filenames, S3 } } } - } - + } + return file_count > 0; } const void upload_bulk(const std::vector& filenames, LLFilePicker::ELoadFilter type) { - // TODO: - // Check user balance for entire cost - // Charge user entire cost - // Loop, uploading - // If an upload fails, refund the user for that one - // - // Also fix single upload to charge first, then refund - - // FIXME PREMIUM what about known types that can't be bulk uploaded - // (bvh)? These will fail in the item by item upload but won't be - // mentioned in the notification. - std::vector filtered_filenames; - for (std::vector::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) - { - const std::string& filename = *in_iter; - if (check_file_extension(filename, type)) - { - filtered_filenames.push_back(filename); - } - } - - S32 expected_upload_cost; - S32 expected_upload_count; - S32 bvh_count; - if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) - { - LLSD args; - args["COST"] = expected_upload_cost; - args["COUNT"] = expected_upload_count; - LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); - - if (filtered_filenames.size() > expected_upload_count) - { - if (bvh_count == filtered_filenames.size() - expected_upload_count) - { - LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); - } - else - { - LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); - } - } - } - else if (bvh_count == filtered_filenames.size()) - { - LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); - } - else - { - LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); - } + // TODO: + // Check user balance for entire cost + // Charge user entire cost + // Loop, uploading + // If an upload fails, refund the user for that one + // + // Also fix single upload to charge first, then refund + + // FIXME PREMIUM what about known types that can't be bulk uploaded + // (bvh)? These will fail in the item by item upload but won't be + // mentioned in the notification. + std::vector filtered_filenames; + for (std::vector::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter) + { + const std::string& filename = *in_iter; + if (check_file_extension(filename, type)) + { + filtered_filenames.push_back(filename); + } + } + + S32 expected_upload_cost; + S32 expected_upload_count; + S32 bvh_count; + if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost, expected_upload_count, bvh_count)) + { + LLSD args; + args["COST"] = expected_upload_cost; + args["COUNT"] = expected_upload_count; + LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); + + if (filtered_filenames.size() > expected_upload_count) + { + if (bvh_count == filtered_filenames.size() - expected_upload_count) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadIncompatibleFiles"); + } + } + } + else if (bvh_count == filtered_filenames.size()) + { + LLNotificationsUtil::add("DoNotSupportBulkAnimationUpload"); + } + else + { + LLNotificationsUtil::add("BulkUploadNoCompatibleFiles"); + } } class LLFileUploadImage : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); + return true; + } }; class LLFileUploadModel : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { + bool handleEvent(const LLSD& userdata) + { LLFloaterModelPreview::showModelPreview(); return TRUE; - } + } }; class LLFileUploadMaterial : public view_listener_t @@ -746,101 +746,101 @@ class LLFileUploadMaterial : public view_listener_t class LLFileUploadSound : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); + return true; + } }; class LLFileUploadAnim : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); + return true; + } }; class LLFileUploadBulk : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); - return true; - } + bool handleEvent(const LLSD& userdata) + { + if (gAgentCamera.cameraMouselook()) + { + gAgentCamera.changeCameraToDefault(); + } + LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); + return true; + } }; -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) +void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) { - LL_WARNS() << error_message << LL_ENDL; - LLNotificationsUtil::add(label, args); - if(LLFile::remove(filename) == -1) - { - LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; - } - LLFilePicker::instance().reset(); + LL_WARNS() << error_message << LL_ENDL; + LLNotificationsUtil::add(label, args); + if(LLFile::remove(filename) == -1) + { + LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; + } + LLFilePicker::instance().reset(); } class LLFileEnableCloseWindow : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); - bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); - return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); - } + return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); + } }; class LLFileCloseWindow : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); - LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); - - if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) - { - snapshot_floater->closeFloater(); - if (gFocusMgr.getKeyboardFocus() == NULL) - { - gFloaterView->focusFrontFloater(); - } - } - else - { - LLFloater::closeFrontmostFloater(); - } - if (gMenuHolder) gMenuHolder->hideMenus(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); + + if(snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) + { + snapshot_floater->closeFloater(); + if (gFocusMgr.getKeyboardFocus() == NULL) + { + gFloaterView->focusFrontFloater(); + } + } + else + { + LLFloater::closeFrontmostFloater(); + } + if (gMenuHolder) gMenuHolder->hideMenus(); + return true; + } }; class LLFileEnableCloseAllWindows : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); - bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()); - bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; - return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown(); - } + bool handleEvent(const LLSD& userdata) + { + LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); + bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()); + bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; + return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown(); + } }; -void close_all_windows() +void close_all_windows() { bool app_quitting = false; gFloaterView->closeAllChildren(app_quitting); @@ -853,112 +853,112 @@ void close_all_windows() class LLFileCloseAllWindows : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - close_all_windows(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + close_all_windows(); + return true; + } }; class LLFileTakeSnapshotToDisk : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLPointer raw = new LLImageRaw; - - S32 width = gViewerWindow->getWindowWidthRaw(); - S32 height = gViewerWindow->getWindowHeightRaw(); - - BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); - BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); - BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); - - BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); - if (high_res) - { - width *= 2; - height *= 2; - // not compatible with UI/HUD - render_ui = false; - render_hud = false; - } - - if (gViewerWindow->rawSnapshot(raw, - width, - height, - TRUE, - FALSE, - render_ui, - render_hud, - FALSE, - render_no_post, - LLSnapshotModel::SNAPSHOT_TYPE_COLOR, - high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side - { - LLPointer formatted; + bool handleEvent(const LLSD& userdata) + { + LLPointer raw = new LLImageRaw; + + S32 width = gViewerWindow->getWindowWidthRaw(); + S32 height = gViewerWindow->getWindowHeightRaw(); + + BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); + BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); + + BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); + if (high_res) + { + width *= 2; + height *= 2; + // not compatible with UI/HUD + render_ui = false; + render_hud = false; + } + + if (gViewerWindow->rawSnapshot(raw, + width, + height, + TRUE, + FALSE, + render_ui, + render_hud, + FALSE, + render_no_post, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side + { + LLPointer formatted; LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); - switch (fmt) - { - case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG: - formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); - break; - default: - LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL; - case LLSnapshotModel::SNAPSHOT_FORMAT_PNG: - formatted = new LLImagePNG; - break; - case LLSnapshotModel::SNAPSHOT_FORMAT_BMP: - formatted = new LLImageBMP; - break; - } - formatted->enableOverSize() ; - formatted->encode(raw, 0); - formatted->disableOverSize() ; - LLSnapshotLivePreview::saveLocal(formatted); - } - return true; - } + switch (fmt) + { + case LLSnapshotModel::SNAPSHOT_FORMAT_JPEG: + formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); + break; + default: + LL_WARNS() << "Unknown local snapshot format: " << fmt << LL_ENDL; + case LLSnapshotModel::SNAPSHOT_FORMAT_PNG: + formatted = new LLImagePNG; + break; + case LLSnapshotModel::SNAPSHOT_FORMAT_BMP: + formatted = new LLImageBMP; + break; + } + formatted->enableOverSize() ; + formatted->encode(raw, 0); + formatted->disableOverSize() ; + LLSnapshotLivePreview::saveLocal(formatted); + } + return true; + } }; class LLFileQuit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLAppViewer::instance()->userQuit(); - return true; - } + bool handleEvent(const LLSD& userdata) + { + LLAppViewer::instance()->userQuit(); + return true; + } }; void handle_compress_image(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) - { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) - { - std::string outfile = infile + ".j2c"; - - LL_INFOS() << "Input: " << infile << LL_ENDL; - LL_INFOS() << "Output: " << outfile << LL_ENDL; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - LL_INFOS() << "Compression complete" << LL_ENDL; - } - else - { - LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; - } - - infile = picker.getNextFile(); - } - } + LLFilePicker& picker = LLFilePicker::instance(); + if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) + { + std::string infile = picker.getFirstFile(); + while (!infile.empty()) + { + std::string outfile = infile + ".j2c"; + + LL_INFOS() << "Input: " << infile << LL_ENDL; + LL_INFOS() << "Output: " << outfile << LL_ENDL; + + BOOL success; + + success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + + if (success) + { + LL_INFOS() << "Compression complete" << LL_ENDL; + } + else + { + LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; + } + + infile = picker.getNextFile(); + } + } } // No convinient check in LLFile, and correct way would be something @@ -966,7 +966,7 @@ void handle_compress_image(void*) // so doing dirty, but OS independent fopen and fseek size_t get_file_size(std::string &filename) { - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -1051,21 +1051,21 @@ void handle_compress_file_test(void*) LLUUID upload_new_resource( - const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata, - bool show_inventory) -{ + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata, + bool show_inventory) +{ LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared( src_filename, @@ -1079,127 +1079,127 @@ LLUUID upload_new_resource( } void upload_done_callback( - const LLUUID& uuid, - void* user_data, - S32 result, - LLExtStat ext_status) // StoreAssetData callback (fixed) + const LLUUID& uuid, + void* user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) { - LLResourceData* data = (LLResourceData*)user_data; - S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; - //LLAssetType::EType pref_loc = data->mPreferredLocation; - BOOL is_balance_sufficient = TRUE; - - if(data) - { - if (result >= 0) - { - LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; - - if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || - LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || - LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) - { - // Charge the user for the upload. - LLViewerRegion* region = gAgent.getRegion(); - - if(!(can_afford_transaction(expected_upload_cost))) - { - LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); - is_balance_sufficient = FALSE; - } - else if(region) - { - // Charge user for upload - gStatusBar->debitBalance(expected_upload_cost); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); - msg->addU8("Flags", 0); - // we tell the sim how much we were expecting to pay so it - // can respond to any discrepancy - msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); - msg->addStringFast(_PREHASH_Description, NULL); - msg->sendReliable(region->getHost()); - } - } - - if(is_balance_sufficient) - { - // Actually add the upload to inventory - LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); - if(folder_id.notNull()) - { - U32 next_owner_perms = data->mNextOwnerPerm; - if(PERM_NONE == next_owner_perms) - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), - data->mAssetInfo.getDescription(), data->mAssetInfo.mType, + LLResourceData* data = (LLResourceData*)user_data; + S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; + //LLAssetType::EType pref_loc = data->mPreferredLocation; + BOOL is_balance_sufficient = TRUE; + + if(data) + { + if (result >= 0) + { + LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; + + if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || + LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || + LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) + { + // Charge the user for the upload. + LLViewerRegion* region = gAgent.getRegion(); + + if(!(can_afford_transaction(expected_upload_cost))) + { + LLBuyCurrencyHTML::openCurrencyFloater( "", expected_upload_cost ); + is_balance_sufficient = FALSE; + } + else if(region) + { + // Charge user for upload + gStatusBar->debitBalance(expected_upload_cost); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoneyTransferRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_MoneyData); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); + msg->addU8("Flags", 0); + // we tell the sim how much we were expecting to pay so it + // can respond to any discrepancy + msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); + msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); + msg->addStringFast(_PREHASH_Description, NULL); + msg->sendReliable(region->getHost()); + } + } + + if(is_balance_sufficient) + { + // Actually add the upload to inventory + LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; + const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); + if(folder_id.notNull()) + { + U32 next_owner_perms = data->mNextOwnerPerm; + if(PERM_NONE == next_owner_perms) + { + next_owner_perms = PERM_MOVE | PERM_TRANSFER; + } + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), + data->mAssetInfo.getDescription(), data->mAssetInfo.mType, data->mInventoryType, NO_INV_SUBTYPE, next_owner_perms, - LLPointer(NULL)); - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } - } - } - else // if(result >= 0) - { - LLSD args; - args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); - args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); - LLNotificationsUtil::add("CannotUploadReason", args); - } - - delete data; - data = NULL; - } - - LLUploadDialog::modalUploadFinished(); - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback; - void *userdata = NULL; - upload_new_resource( - next_file, - asset_name, - asset_name, // file - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } + LLPointer(NULL)); + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } + } + } + else // if(result >= 0) + { + LLSD args; + args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); + args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); + LLNotificationsUtil::add("CannotUploadReason", args); + } + + delete data; + data = NULL; + } + + LLUploadDialog::modalUploadFinished(); + + // *NOTE: This is a pretty big hack. What this does is check the + // file picker if there are any more pending uploads. If so, + // upload that file. + const std::string& next_file = LLFilePicker::instance().getNextFile(); + if(is_balance_sufficient && !next_file.empty()) + { + std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); + LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string display_name = LLStringUtil::null; + LLAssetStorage::LLStoreAssetCallback callback; + void *userdata = NULL; + upload_new_resource( + next_file, + asset_name, + asset_name, // file + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + display_name, + callback, + expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost + userdata); + } } void upload_new_resource( @@ -1207,90 +1207,90 @@ void upload_new_resource( LLAssetStorage::LLStoreAssetCallback callback, void *userdata) { - if(gDisconnected) - { - return ; - } + if(gDisconnected) + { + return ; + } // uploadInfo->setAssetType(assetType); // uploadInfo->setTransactionId(tid); - std::string url = gAgent.getRegionCapability("NewFileAgentInventory"); + std::string url = gAgent.getRegionCapability("NewFileAgentInventory"); - if ( !url.empty() ) - { + if ( !url.empty() ) + { LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); - } - else - { + } + else + { uploadInfo->prepareUpload(); uploadInfo->logPreparedUpload(); - LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; - // check for adequate funds - // TODO: do this check on the sim - if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || + LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; + // check for adequate funds + // TODO: do this check on the sim + if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() || LLAssetType::AT_ANIMATION == uploadInfo->getAssetType()) - { - S32 balance = gStatusBar->getBalance(); - if (balance < uploadInfo->getExpectedUploadCost()) - { - // insufficient funds, bail on this upload + { + S32 balance = gStatusBar->getBalance(); + if (balance < uploadInfo->getExpectedUploadCost()) + { + // insufficient funds, bail on this upload LLBuyCurrencyHTML::openCurrencyFloater("", uploadInfo->getExpectedUploadCost()); - return; - } - } + return; + } + } - LLResourceData* data = new LLResourceData; - data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); - data->mAssetInfo.mUuid = uploadInfo->getAssetId(); + LLResourceData* data = new LLResourceData; + data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); + data->mAssetInfo.mUuid = uploadInfo->getAssetId(); data->mAssetInfo.mType = uploadInfo->getAssetType(); - data->mAssetInfo.mCreatorID = gAgentID; - data->mInventoryType = uploadInfo->getInventoryType(); - data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); - data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); - data->mUserData = userdata; - data->mAssetInfo.setName(uploadInfo->getName()); - data->mAssetInfo.setDescription(uploadInfo->getDescription()); - data->mPreferredLocation = uploadInfo->getDestinationFolderType(); - - LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; - if (callback) - { - asset_callback = callback; - } - gAssetStorage->storeAssetData( - data->mAssetInfo.mTransactionID, - data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); - } + data->mAssetInfo.mCreatorID = gAgentID; + data->mInventoryType = uploadInfo->getInventoryType(); + data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); + data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); + data->mUserData = userdata; + data->mAssetInfo.setName(uploadInfo->getName()); + data->mAssetInfo.setDescription(uploadInfo->getDescription()); + data->mPreferredLocation = uploadInfo->getDestinationFolderType(); + + LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; + if (callback) + { + asset_callback = callback; + } + gAssetStorage->storeAssetData( + data->mAssetInfo.mTransactionID, + data->mAssetInfo.mType, + asset_callback, + (void*)data, + FALSE); + } } void init_menu_file() { - view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); - view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); - view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); - view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); + view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); + view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); + view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); + view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); view_listener_t::addCommit(new LLFileUploadMaterial(), "File.UploadMaterial"); - view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); - view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); - view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); - view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); - view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); - view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); - view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); - - view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); - view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); + view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); + view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); + view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); + view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); + view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); + view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); + view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); + + view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); + view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); view_listener_t::addEnable(new LLFileEnableUploadMaterial(), "File.EnableUploadMaterial"); - view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); - view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); + view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); + view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); - // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. + // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index d41aa23829..5bf78a2c7f 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewermenufile.h * @brief "File" menu in the main menu bar. * * $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$ */ @@ -66,11 +66,11 @@ void upload_new_resource( void assign_defaults_and_show_upload_message( - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description); + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description); void close_all_windows(); @@ -79,39 +79,39 @@ class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) public: - static std::queue sDeadQ; - static LLMutex* sMutex; + static std::queue sDeadQ; + static LLMutex* sMutex; - static void initClass(); - static void cleanupClass(); - static void clearDead(); + static void initClass(); + static void cleanupClass(); + static void clearDead(); - std::vector mResponses; - std::string mProposedName; + std::vector mResponses; + std::string mProposedName; - LLFilePicker::ELoadFilter mLoadFilter; - LLFilePicker::ESaveFilter mSaveFilter; - bool mIsSaveDialog; - bool mIsGetMultiple; + LLFilePicker::ELoadFilter mLoadFilter; + LLFilePicker::ESaveFilter mSaveFilter; + bool mIsSaveDialog; + bool mIsGetMultiple; - LLFilePickerThread(LLFilePicker::ELoadFilter filter, bool get_multiple = false) - : LLThread("file picker"), mLoadFilter(filter), mIsSaveDialog(false), mIsGetMultiple(get_multiple) - { - } + LLFilePickerThread(LLFilePicker::ELoadFilter filter, bool get_multiple = false) + : LLThread("file picker"), mLoadFilter(filter), mIsSaveDialog(false), mIsGetMultiple(get_multiple) + { + } - LLFilePickerThread(LLFilePicker::ESaveFilter filter, const std::string &proposed_name) - : LLThread("file picker"), mSaveFilter(filter), mIsSaveDialog(true), mProposedName(proposed_name) - { - } + LLFilePickerThread(LLFilePicker::ESaveFilter filter, const std::string &proposed_name) + : LLThread("file picker"), mSaveFilter(filter), mIsSaveDialog(true), mProposedName(proposed_name) + { + } - void getFile(); + void getFile(); - virtual void run(); + virtual void run(); void runModeless(); static void modelessStringCallback(bool success, std::string &response, void *user_data); static void modelessVectorCallback(bool success, std::vector &responses, void *user_data); - virtual void notify(const std::vector& filenames) = 0; + virtual void notify(const std::vector& filenames) = 0; }; @@ -119,12 +119,12 @@ class LLFilePickerReplyThread : public LLFilePickerThread { public: - typedef boost::signals2::signal& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; + typedef boost::signals2::signal& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; static void startPicker(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); static void startPicker(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); - virtual void notify(const std::vector& filenames); + virtual void notify(const std::vector& filenames); private: LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); @@ -132,10 +132,10 @@ private: ~LLFilePickerReplyThread(); private: - LLFilePicker::ELoadFilter mLoadFilter; - LLFilePicker::ESaveFilter mSaveFilter; - file_picked_signal_t* mFilePickedSignal; - file_picked_signal_t* mFailureSignal; + LLFilePicker::ELoadFilter mLoadFilter; + LLFilePicker::ESaveFilter mSaveFilter; + file_picked_signal_t* mFilePickedSignal; + file_picked_signal_t* mFailureSignal; }; class LLMediaFilePicker : public LLFilePickerThread diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e8b81ac3b4..4e4b4db38d 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewermessage.cpp * @brief Dumping ground for viewer-side message system callbacks. * * $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$ */ @@ -29,9 +29,9 @@ // Linden libraries #include "llanimationstates.h" -#include "llaudioengine.h" +#include "llaudioengine.h" #include "llavataractions.h" -#include "llavatarnamecache.h" // IDEVO HACK +#include "llavatarnamecache.h" // IDEVO HACK #include "lleventtimer.h" #include "llfloatercreatelandmark.h" #include "llfloaterreg.h" @@ -91,7 +91,7 @@ #include "lltrans.h" #include "lltranslate.h" #include "llviewerfoldertype.h" -#include "llvoavatar.h" // IDEVO HACK +#include "llvoavatar.h" // IDEVO HACK #include "lluri.h" #include "llviewergenericmessage.h" #include "llviewermenu.h" @@ -136,8 +136,8 @@ const F32 CAMERA_POSITION_THRESHOLD_SQUARED = 0.001f * 0.001f; // Determine how quickly residents' scripts can issue question dialogs // Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in -static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests -static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds +static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests +static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds extern BOOL gDebugClicks; extern bool gShiftFrame; @@ -154,9 +154,9 @@ const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds // Agent Update Flags (U8) -const U8 AU_FLAGS_NONE = 0x00; -const U8 AU_FLAGS_HIDETITLE = 0x01; -const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02; +const U8 AU_FLAGS_NONE = 0x00; +const U8 AU_FLAGS_HIDETITLE = 0x01; +const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02; void accept_friendship_coro(std::string url, LLSD notification) { @@ -253,25 +253,25 @@ void decline_friendship_coro(std::string url, LLSD notification, S32 option) bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem* msg = gMessageSystem; - const LLSD& payload = notification["payload"]; - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLMessageSystem* msg = gMessageSystem; + const LLSD& payload = notification["payload"]; + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); // this will be skipped if the user offering friendship is blocked if (notification_ptr) { - switch(option) - { - case 0: - { - LLUIUsage::instance().logCommand("Agent.AcceptFriendship"); - // accept - LLAvatarTracker::formFriendship(payload["from_id"]); + switch(option) + { + case 0: + { + LLUIUsage::instance().logCommand("Agent.AcceptFriendship"); + // accept + LLAvatarTracker::formFriendship(payload["from_id"]); - const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - // This will also trigger an onlinenotification if the user is online + // This will also trigger an onlinenotification if the user is online std::string url = gAgent.getRegionCapability("AcceptFriendship"); LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) @@ -302,15 +302,15 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { LL_WARNS("Friendship") << "Failed to accept friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; } - break; - } - case 1: // Decline - // fall-through - case 2: // Send IM - decline and start IM session - { - LLUIUsage::instance().logCommand("Agent.DeclineFriendship"); - // decline - // We no longer notify other viewers, but we DO still send + break; + } + case 1: // Decline + // fall-through + case 2: // Send IM - decline and start IM session + { + LLUIUsage::instance().logCommand("Agent.DeclineFriendship"); + // decline + // We no longer notify other viewers, but we DO still send // the rejection to the simulator to delete the pending userop. std::string url = gAgent.getRegionCapability("DeclineFriendship"); LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; @@ -346,24 +346,24 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { LL_WARNS("Friendship") << "Failed to decline friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; } - } - default: - // close button probably, possibly timed out - break; - } + } + default: + // close button probably, possibly timed out + break; + } - // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): - // here appears three additional toasts instead one modified - // need investigation and fix + // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): + // here appears three additional toasts instead one modified + // need investigation and fix - // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); - // modified_form->setElementEnabled("Accept", false); - // modified_form->setElementEnabled("Decline", false); - // notification_ptr->updateForm(modified_form); - // notification_ptr->repost(); + // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + // modified_form->setElementEnabled("Accept", false); + // modified_form->setElementEnabled("Decline", false); + // notification_ptr->updateForm(modified_form); + // notification_ptr->repost(); } - return false; + return false; } static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); @@ -372,139 +372,139 @@ static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("Offer // void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group, - S32 trx_type, const std::string& desc) -{ - if(0 == amount || !region) return; - amount = abs(amount); - LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; - if(can_afford_transaction(amount)) - { - if (uuid.isNull()) - { - LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; - return; - } -// gStatusBar->debitBalance(amount); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + S32 trx_type, const std::string& desc) +{ + if(0 == amount || !region) return; + amount = abs(amount); + LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; + if(can_afford_transaction(amount)) + { + if (uuid.isNull()) + { + LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; + return; + } +// gStatusBar->debitBalance(amount); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoneyTransferRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_DestID, uuid); - msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); - msg->addS32Fast(_PREHASH_Amount, amount); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, trx_type ); - msg->addStringFast(_PREHASH_Description, desc); - msg->sendReliable(region->getHost()); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", amount); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount ); - } + msg->nextBlockFast(_PREHASH_MoneyData); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_DestID, uuid); + msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); + msg->addS32Fast(_PREHASH_Amount, amount); + msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); + msg->addS32Fast(_PREHASH_TransactionType, trx_type ); + msg->addStringFast(_PREHASH_Description, desc); + msg->sendReliable(region->getHost()); + } + else + { + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", amount); + LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount ); + } } void send_complete_agent_movement(const LLHost& sim_host) { - LL_DEBUGS("Teleport", "Messaging") << "Sending CompleteAgentMovement to sim_host " << sim_host << LL_ENDL; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_CompleteAgentMovement); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode); - msg->sendReliable(sim_host); + LL_DEBUGS("Teleport", "Messaging") << "Sending CompleteAgentMovement to sim_host " << sim_host << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_CompleteAgentMovement); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode); + msg->sendReliable(sim_host); } void process_logout_reply(LLMessageSystem* msg, void**) { - // The server has told us it's ok to quit. - LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL; - - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - LLUUID session_id; - msg->getUUID("AgentData", "SessionID", session_id); - if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) - { - LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; - } - - LLInventoryModel::update_map_t parents; - S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); - for(S32 i = 0; i < count; ++i) - { - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - - if( (1 == count) && item_id.isNull() ) - { - // Detect dummy item. Indicates an empty list. - break; - } - - // We do not need to track the asset ids, just account for an - // updated inventory version. - LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; - LLInventoryItem* item = gInventory.getItem( item_id ); - if( item ) - { - parents[item->getParentUUID()] = 0; - gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); - } - else - { - LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL; - } - } + // The server has told us it's ok to quit. + LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL; + + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + LLUUID session_id; + msg->getUUID("AgentData", "SessionID", session_id); + if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) + { + LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; + } + + LLInventoryModel::update_map_t parents; + S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); + for(S32 i = 0; i < count; ++i) + { + LLUUID item_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); + + if( (1 == count) && item_id.isNull() ) + { + // Detect dummy item. Indicates an empty list. + break; + } + + // We do not need to track the asset ids, just account for an + // updated inventory version. + LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; + LLInventoryItem* item = gInventory.getItem( item_id ); + if( item ) + { + parents[item->getParentUUID()] = 0; + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); + } + else + { + LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL; + } + } LLAppViewer::instance()->forceQuit(); } void process_layer_data(LLMessageSystem *mesgsys, void **user_data) { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); - - LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; - - if(!regionp) - { - LL_WARNS() << "Invalid region for layer data." << LL_ENDL; - return; - } - S32 size; - S8 type; - - mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type); - size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data); - if (0 == size) - { - LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL; - return; - } - if (size < 0) - { - // getSizeFast() is probably trying to tell us about an error - LL_WARNS("Messaging") << "getSizeFast() returned negative result: " - << size - << LL_ENDL; - return; - } - U8 *datap = new U8[size]; - mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); - LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); - if (mesgsys->getReceiveCompressedSize()) - { - gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveCompressedSize()); - } - else - { - gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveSize()); - } + LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); + + LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; + + if(!regionp) + { + LL_WARNS() << "Invalid region for layer data." << LL_ENDL; + return; + } + S32 size; + S8 type; + + mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type); + size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data); + if (0 == size) + { + LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL; + return; + } + if (size < 0) + { + // getSizeFast() is probably trying to tell us about an error + LL_WARNS("Messaging") << "getSizeFast() returned negative result: " + << size + << LL_ENDL; + return; + } + U8 *datap = new U8[size]; + mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); + LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); + if (mesgsys->getReceiveCompressedSize()) + { + gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveCompressedSize()); + } + else + { + gVLManager.addLayerData(vl_datap, (S32Bytes)mesgsys->getReceiveSize()); + } } // S32 exported_object_count = 0; @@ -524,223 +524,223 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) // void export_complete() // { -// LLUploadDialog::modalUploadFinished(); -// gExporterRequestID.setNull(); -// gExportDirectory = ""; - -// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ -// fseek(fXML, 0, SEEK_END); -// long length = ftell(fXML); -// fseek(fXML, 0, SEEK_SET); -// U8 *buffer = new U8[length + 1]; -// size_t nread = fread(buffer, 1, length, fXML); -// if (nread < (size_t) length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// buffer[nread] = '\0'; -// fclose(fXML); - -// char *pos = (char *)buffer; -// while ((pos = strstr(pos+1, ""); - -// if (pos_uuid) -// { -// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ -// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ -// image_uuid_str[UUID_STR_SIZE-1] = 0; - -// LLUUID image_uuid(image_uuid_str); - -// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; - -// std::map::iterator itor = gImageChecksums.find(image_uuid); -// if (itor != gImageChecksums.end()) -// { -// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; -// if (!itor->second.empty()) -// { -// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ -// } -// } -// } -// } -// } - -// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ -// if (fwrite(buffer, 1, length, fXMLOut) != length) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fclose(fXMLOut); - -// delete [] buffer; +// LLUploadDialog::modalUploadFinished(); +// gExporterRequestID.setNull(); +// gExportDirectory = ""; + +// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ +// fseek(fXML, 0, SEEK_END); +// long length = ftell(fXML); +// fseek(fXML, 0, SEEK_SET); +// U8 *buffer = new U8[length + 1]; +// size_t nread = fread(buffer, 1, length, fXML); +// if (nread < (size_t) length) +// { +// LL_WARNS("Messaging") << "Short read" << LL_ENDL; +// } +// buffer[nread] = '\0'; +// fclose(fXML); + +// char *pos = (char *)buffer; +// while ((pos = strstr(pos+1, ""); + +// if (pos_uuid) +// { +// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ +// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ +// image_uuid_str[UUID_STR_SIZE-1] = 0; + +// LLUUID image_uuid(image_uuid_str); + +// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; + +// std::map::iterator itor = gImageChecksums.find(image_uuid); +// if (itor != gImageChecksums.end()) +// { +// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; +// if (!itor->second.empty()) +// { +// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ +// } +// } +// } +// } +// } + +// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ +// if (fwrite(buffer, 1, length, fXMLOut) != length) +// { +// LL_WARNS("Messaging") << "Short write" << LL_ENDL; +// } +// fclose(fXMLOut); + +// delete [] buffer; // } // void exported_item_complete(const LLTSCode status, void *user_data) // { -// //std::string *filename = (std::string *)user_data; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; -// } -// else -// { -// ++current_object_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; - -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -// } +// //std::string *filename = (std::string *)user_data; + +// if (status < LLTS_OK) +// { +// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; +// } +// else +// { +// ++current_object_count; +// if (current_image_count == exported_image_count && current_object_count == exported_object_count) +// { +// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; + +// export_complete(); +// } +// else +// { +// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); +// } +// } // } // struct exported_image_info // { -// LLUUID image_id; -// std::string filename; -// U32 image_num; +// LLUUID image_id; +// std::string filename; +// U32 image_num; // }; // void exported_j2c_complete(const LLTSCode status, void *user_data) // { -// exported_image_info *info = (exported_image_info *)user_data; -// LLUUID image_id = info->image_id; -// U32 image_num = info->image_num; -// std::string filename = info->filename; -// delete info; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; -// } -// else -// { -// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ -// if (fIn) -// { -// LLPointer ImageUtility = new LLImageJ2C; -// LLPointer TargaUtility = new LLImageTGA; - -// fseek(fIn, 0, SEEK_END); -// S32 length = ftell(fIn); -// fseek(fIn, 0, SEEK_SET); -// U8 *buffer = ImageUtility->allocateData(length); -// if (fread(buffer, 1, length, fIn) != length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// fclose(fIn); -// LLFile::remove(filename); - -// // Convert to TGA -// LLPointer image = new LLImageRaw(); - -// ImageUtility->updateData(); -// ImageUtility->decode(image, 100000.0f); - -// TargaUtility->encode(image); -// U8 *data = TargaUtility->getData(); -// S32 data_size = TargaUtility->getDataSize(); - -// std::string file_path = gDirUtilp->getDirName(filename); - -// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; -// //S32 name_len = output_file.length(); -// //strcpy(&output_file[name_len-3], "tga"); -// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ -// char md5_hash_string[33]; /* Flawfinder: ignore */ -// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ -// if (fOut) -// { -// if (fwrite(data, 1, data_size, fOut) != data_size) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fseek(fOut, 0, SEEK_SET); -// fclose(fOut); -// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ -// LLMD5 my_md5_hash(fOut); -// my_md5_hash.hex_digest(md5_hash_string); -// } - -// gImageChecksums.insert(std::pair(image_id, md5_hash_string)); -// } -// } - -// ++current_image_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } +// exported_image_info *info = (exported_image_info *)user_data; +// LLUUID image_id = info->image_id; +// U32 image_num = info->image_num; +// std::string filename = info->filename; +// delete info; + +// if (status < LLTS_OK) +// { +// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; +// } +// else +// { +// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ +// if (fIn) +// { +// LLPointer ImageUtility = new LLImageJ2C; +// LLPointer TargaUtility = new LLImageTGA; + +// fseek(fIn, 0, SEEK_END); +// S32 length = ftell(fIn); +// fseek(fIn, 0, SEEK_SET); +// U8 *buffer = ImageUtility->allocateData(length); +// if (fread(buffer, 1, length, fIn) != length) +// { +// LL_WARNS("Messaging") << "Short read" << LL_ENDL; +// } +// fclose(fIn); +// LLFile::remove(filename); + +// // Convert to TGA +// LLPointer image = new LLImageRaw(); + +// ImageUtility->updateData(); +// ImageUtility->decode(image, 100000.0f); + +// TargaUtility->encode(image); +// U8 *data = TargaUtility->getData(); +// S32 data_size = TargaUtility->getDataSize(); + +// std::string file_path = gDirUtilp->getDirName(filename); + +// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; +// //S32 name_len = output_file.length(); +// //strcpy(&output_file[name_len-3], "tga"); +// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ +// char md5_hash_string[33]; /* Flawfinder: ignore */ +// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ +// if (fOut) +// { +// if (fwrite(data, 1, data_size, fOut) != data_size) +// { +// LL_WARNS("Messaging") << "Short write" << LL_ENDL; +// } +// fseek(fOut, 0, SEEK_SET); +// fclose(fOut); +// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ +// LLMD5 my_md5_hash(fOut); +// my_md5_hash.hex_digest(md5_hash_string); +// } + +// gImageChecksums.insert(std::pair(image_id, md5_hash_string)); +// } +// } + +// ++current_image_count; +// if (current_image_count == exported_image_count && current_object_count == exported_object_count) +// { +// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; +// export_complete(); +// } +// else +// { +// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); +// } //} void process_derez_ack(LLMessageSystem*, void**) { - if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); + if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); } void process_places_reply(LLMessageSystem* msg, void** data) { - LLUUID query_id; + LLUUID query_id; - msg->getUUID("AgentData", "QueryID", query_id); - if (query_id.isNull()) - { - LLFloaterLandHoldings::processPlacesReply(msg, data); - } - else if(gAgent.isInGroup(query_id)) - { - LLPanelGroupLandMoney::processPlacesReply(msg, data); - } - else - { - LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL; - } + msg->getUUID("AgentData", "QueryID", query_id); + if (query_id.isNull()) + { + LLFloaterLandHoldings::processPlacesReply(msg, data); + } + else if(gAgent.isInGroup(query_id)) + { + LLPanelGroupLandMoney::processPlacesReply(msg, data); + } + else + { + LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL; + } } void send_sound_trigger(const LLUUID& sound_id, F32 gain) { - if (sound_id.isNull() || gAgent.getRegion() == NULL) - { - // disconnected agent or zero guids don't get sent (no sound) - return; - } + if (sound_id.isNull() || gAgent.getRegion() == NULL) + { + // disconnected agent or zero guids don't get sent (no sound) + return; + } - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SoundTrigger); - msg->nextBlockFast(_PREHASH_SoundData); - msg->addUUIDFast(_PREHASH_SoundID, sound_id); - // Client untrusted, ids set on sim - msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_SoundTrigger); + msg->nextBlockFast(_PREHASH_SoundData); + msg->addUUIDFast(_PREHASH_SoundID, sound_id); + // Client untrusted, ids set on sim + msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); - msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); + msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); - LLVector3 position = gAgent.getPositionAgent(); - msg->addVector3Fast(_PREHASH_Position, position); - msg->addF32Fast(_PREHASH_Gain, gain); + LLVector3 position = gAgent.getPositionAgent(); + msg->addVector3Fast(_PREHASH_Position, position); + msg->addF32Fast(_PREHASH_Gain, gain); - gAgent.sendMessage(); + gAgent.sendMessage(); } static LLSD sSavedGroupInvite; @@ -839,10 +839,10 @@ void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accep EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE; - if (accept_invite) - { - LLUIUsage::instance().logCommand("Group.Join"); - } + if (accept_invite) + { + LLUIUsage::instance().logCommand("Group.Join"); + } send_improved_im(group_id, std::string("name"), @@ -868,122 +868,122 @@ void send_join_group_response(LLUUID group_id, LLUUID transaction_id, bool accep bool join_group_response(const LLSD& notification, const LLSD& response) { -// A bit of variable saving and restoring is used to deal with the case where your group list is full and you -// receive an invitation to another group. The data from that invitation is stored in the sSaved -// variables. If you then drop a group and click on the Join button the stored data is restored and used -// to join the group. - LLSD notification_adjusted = notification; - LLSD response_adjusted = response; - - std::string action = notification["name"]; - -// Storing all the information by group id allows for the rare case of being at your maximum -// group count and receiving more than one invitation. - std::string id = notification_adjusted["payload"]["group_id"].asString(); - - if ("JoinGroup" == action || "JoinGroupCanAfford" == action) - { - sSavedGroupInvite[id] = notification; - sSavedResponse[id] = response; - } - else if ("JoinedTooManyGroupsMember" == action) - { - S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == opt) // Join button pressed - { - notification_adjusted = sSavedGroupInvite[id]; - response_adjusted = sSavedResponse[id]; - } - } - - S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); - bool accept_invite = false; - - LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); - LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); - std::string name = notification_adjusted["payload"]["name"].asString(); - std::string message = notification_adjusted["payload"]["message"].asString(); - S32 fee = notification_adjusted["payload"]["fee"].asInteger(); - U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); - - if (option == 2 && !group_id.isNull()) - { - LLGroupActions::show(group_id); - LLSD args; - args["MESSAGE"] = message; - LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); - return false; - } - - if(option == 0 && !group_id.isNull()) - { - // check for promotion or demotion. - S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); - if(gAgent.isInGroup(group_id)) ++max_groups; - - if(gAgent.mGroups.size() < max_groups) - { - accept_invite = true; - } - else - { - LLSD args; - args["NAME"] = name; - LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification_adjusted["payload"]); - return false; - } - } - send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); - - sSavedGroupInvite[id] = LLSD::emptyMap(); - sSavedResponse[id] = LLSD::emptyMap(); - - return false; +// A bit of variable saving and restoring is used to deal with the case where your group list is full and you +// receive an invitation to another group. The data from that invitation is stored in the sSaved +// variables. If you then drop a group and click on the Join button the stored data is restored and used +// to join the group. + LLSD notification_adjusted = notification; + LLSD response_adjusted = response; + + std::string action = notification["name"]; + +// Storing all the information by group id allows for the rare case of being at your maximum +// group count and receiving more than one invitation. + std::string id = notification_adjusted["payload"]["group_id"].asString(); + + if ("JoinGroup" == action || "JoinGroupCanAfford" == action) + { + sSavedGroupInvite[id] = notification; + sSavedResponse[id] = response; + } + else if ("JoinedTooManyGroupsMember" == action) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == opt) // Join button pressed + { + notification_adjusted = sSavedGroupInvite[id]; + response_adjusted = sSavedResponse[id]; + } + } + + S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); + bool accept_invite = false; + + LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); + LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); + std::string name = notification_adjusted["payload"]["name"].asString(); + std::string message = notification_adjusted["payload"]["message"].asString(); + S32 fee = notification_adjusted["payload"]["fee"].asInteger(); + U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); + + if (option == 2 && !group_id.isNull()) + { + LLGroupActions::show(group_id); + LLSD args; + args["MESSAGE"] = message; + LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); + return false; + } + + if(option == 0 && !group_id.isNull()) + { + // check for promotion or demotion. + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); + if(gAgent.isInGroup(group_id)) ++max_groups; + + if(gAgent.mGroups.size() < max_groups) + { + accept_invite = true; + } + else + { + LLSD args; + args["NAME"] = name; + LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification_adjusted["payload"]); + return false; + } + } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); + + sSavedGroupInvite[id] = LLSD::emptyMap(); + sSavedResponse[id] = LLSD::emptyMap(); + + return false; } static void highlight_inventory_objects_in_panel(const std::vector& items, LLInventoryPanel *inventory_panel) { - if (NULL == inventory_panel) return; - - for (std::vector::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) - { - const LLUUID& item_id = (*item_iter); - if(!highlight_offered_object(item_id)) - { - continue; - } - - LLInventoryObject* item = gInventory.getObject(item_id); - llassert(item); - if (!item) { - continue; - } - - LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; - LLFolderView* fv = inventory_panel->getRootFolder(); - if (fv) - { - LLFolderViewItem* fv_item = inventory_panel->getItemByID(item_id); - if (fv_item) - { - LLFolderViewItem* fv_folder = fv_item->getParentFolder(); - if (fv_folder) - { - // Parent folders can be different in case of 2 consecutive drag and drop - // operations when the second one is started before the first one completes. - LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; - fv_folder->setOpen(TRUE); - if (fv_folder->isSelected()) - { - fv->changeSelection(fv_folder, FALSE); - } - } - fv->changeSelection(fv_item, TRUE); - } - } - } + if (NULL == inventory_panel) return; + + for (std::vector::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + if(!highlight_offered_object(item_id)) + { + continue; + } + + LLInventoryObject* item = gInventory.getObject(item_id); + llassert(item); + if (!item) { + continue; + } + + LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; + LLFolderView* fv = inventory_panel->getRootFolder(); + if (fv) + { + LLFolderViewItem* fv_item = inventory_panel->getItemByID(item_id); + if (fv_item) + { + LLFolderViewItem* fv_folder = fv_item->getParentFolder(); + if (fv_folder) + { + // Parent folders can be different in case of 2 consecutive drag and drop + // operations when the second one is started before the first one completes. + LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; + fv_folder->setOpen(TRUE); + if (fv_folder->isSelected()) + { + fv->changeSelection(fv_folder, FALSE); + } + } + fv->changeSelection(fv_item, TRUE); + } + } + } } static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response); @@ -997,30 +997,30 @@ static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_ class LLOpenAgentOffer : public LLInventoryFetchItemsObserver { public: - LLOpenAgentOffer(const LLUUID& object_id, - const std::string& from_name) : - LLInventoryFetchItemsObserver(object_id), - mFromName(from_name) {} - /*virtual*/ void startFetch() - { - for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if (cat) - { - mComplete.push_back((*it)); - } - } - LLInventoryFetchItemsObserver::startFetch(); - } - /*virtual*/ void done() - { - open_inventory_offer(mComplete, mFromName); - gInventory.removeObserver(this); - delete this; - } + LLOpenAgentOffer(const LLUUID& object_id, + const std::string& from_name) : + LLInventoryFetchItemsObserver(object_id), + mFromName(from_name) {} + /*virtual*/ void startFetch() + { + for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if (cat) + { + mComplete.push_back((*it)); + } + } + LLInventoryFetchItemsObserver::startFetch(); + } + /*virtual*/ void done() + { + open_inventory_offer(mComplete, mFromName); + gInventory.removeObserver(this); + delete this; + } private: - std::string mFromName; + std::string mFromName; }; /** @@ -1032,117 +1032,117 @@ private: class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver { public: - LLViewerInventoryMoveFromWorldObserver() - : LLInventoryAddItemByAssetObserver() - { + LLViewerInventoryMoveFromWorldObserver() + : LLInventoryAddItemByAssetObserver() + { - } + } - void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } private: - /*virtual */void onAssetAdded(const LLUUID& asset_id) - { - // Store active Inventory panel. - if (LLInventoryPanel::getActiveInventoryPanel()) - { - mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); - } - - // Store selected items (without destination folder) - mSelectedItems.clear(); - if (LLInventoryPanel::getActiveInventoryPanel()) - { - std::set selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); - for (std::set::iterator it = selection.begin(), end_it = selection.end(); - it != end_it; - ++it) - { - mSelectedItems.insert(static_cast((*it)->getViewModelItem())->getUUID()); - } - } - mSelectedItems.erase(mMoveIntoFolderID); - } - - /** - * Selects added inventory items watched by their Asset UUIDs if selection was not changed since - * all items were started to watch (dropped into a folder). - */ - void done() - { - LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); - - // if selection is not changed since watch started lets hightlight new items. - if (active_panel && !isSelectionChanged()) - { - LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; - active_panel->clearSelection(); - highlight_inventory_objects_in_panel(mAddedItems, active_panel); - } - } - - /** - * Returns true if selected inventory items were changed since moved inventory items were started to watch. - */ - bool isSelectionChanged() - { - LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); - - if (NULL == active_panel) - { - return true; - } - - // get selected items (without destination folder) - selected_items_t selected_items; - - std::set selection = active_panel->getRootFolder()->getSelectionList(); - for (std::set::iterator it = selection.begin(), end_it = selection.end(); - it != end_it; - ++it) - { - selected_items.insert(static_cast((*it)->getViewModelItem())->getUUID()); - } - selected_items.erase(mMoveIntoFolderID); - - // compare stored & current sets of selected items - selected_items_t different_items; - std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), - selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); - - LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() - << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; - - return different_items.size() > 0; - } - - LLHandle mActivePanel; - typedef std::set selected_items_t; - selected_items_t mSelectedItems; - - /** - * UUID of FolderViewFolder into which watched items are moved. - * - * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). - * - * If mouse is moved out it set unselected and number of selected items is changed - * even if selected items in Inventory stay the same. - * So, it is used to update stored selection list. - * - * @see onAssetAdded() - * @see isSelectionChanged() - */ - LLUUID mMoveIntoFolderID; + /*virtual */void onAssetAdded(const LLUUID& asset_id) + { + // Store active Inventory panel. + if (LLInventoryPanel::getActiveInventoryPanel()) + { + mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); + } + + // Store selected items (without destination folder) + mSelectedItems.clear(); + if (LLInventoryPanel::getActiveInventoryPanel()) + { + std::set selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); + for (std::set::iterator it = selection.begin(), end_it = selection.end(); + it != end_it; + ++it) + { + mSelectedItems.insert(static_cast((*it)->getViewModelItem())->getUUID()); + } + } + mSelectedItems.erase(mMoveIntoFolderID); + } + + /** + * Selects added inventory items watched by their Asset UUIDs if selection was not changed since + * all items were started to watch (dropped into a folder). + */ + void done() + { + LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); + + // if selection is not changed since watch started lets hightlight new items. + if (active_panel && !isSelectionChanged()) + { + LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; + active_panel->clearSelection(); + highlight_inventory_objects_in_panel(mAddedItems, active_panel); + } + } + + /** + * Returns true if selected inventory items were changed since moved inventory items were started to watch. + */ + bool isSelectionChanged() + { + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); + + if (NULL == active_panel) + { + return true; + } + + // get selected items (without destination folder) + selected_items_t selected_items; + + std::set selection = active_panel->getRootFolder()->getSelectionList(); + for (std::set::iterator it = selection.begin(), end_it = selection.end(); + it != end_it; + ++it) + { + selected_items.insert(static_cast((*it)->getViewModelItem())->getUUID()); + } + selected_items.erase(mMoveIntoFolderID); + + // compare stored & current sets of selected items + selected_items_t different_items; + std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), + selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); + + LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() + << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; + + return different_items.size() > 0; + } + + LLHandle mActivePanel; + typedef std::set selected_items_t; + selected_items_t mSelectedItems; + + /** + * UUID of FolderViewFolder into which watched items are moved. + * + * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). + * + * If mouse is moved out it set unselected and number of selected items is changed + * even if selected items in Inventory stay the same. + * So, it is used to update stored selection list. + * + * @see onAssetAdded() + * @see isSelectionChanged() + */ + LLUUID mMoveIntoFolderID; }; LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) { - start_new_inventory_observer(); + start_new_inventory_observer(); - gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); - gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); + gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); + gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); } @@ -1156,124 +1156,124 @@ class LLViewerInventoryMoveObserver : public LLInventoryObserver { public: - LLViewerInventoryMoveObserver(const LLUUID& object_id) - : LLInventoryObserver() - , mObjectID(object_id) - { - if (LLInventoryPanel::getActiveInventoryPanel()) - { - mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); - } - } - - virtual ~LLViewerInventoryMoveObserver() {} - virtual void changed(U32 mask); - + LLViewerInventoryMoveObserver(const LLUUID& object_id) + : LLInventoryObserver() + , mObjectID(object_id) + { + if (LLInventoryPanel::getActiveInventoryPanel()) + { + mActivePanel = LLInventoryPanel::getActiveInventoryPanel()->getHandle(); + } + } + + virtual ~LLViewerInventoryMoveObserver() {} + virtual void changed(U32 mask); + private: - LLUUID mObjectID; - LLHandle mActivePanel; + LLUUID mObjectID; + LLHandle mActivePanel; }; void LLViewerInventoryMoveObserver::changed(U32 mask) { - LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); - - if (NULL == active_panel) - { - gInventory.removeObserver(this); - return; - } - - if((mask & (LLInventoryObserver::STRUCTURE)) != 0) - { - const std::set& changed_items = gInventory.getChangedIDs(); - - std::set::const_iterator id_it = changed_items.begin(); - std::set::const_iterator id_end = changed_items.end(); - for (;id_it != id_end; ++id_it) - { - if ((*id_it) == mObjectID) - { - active_panel->clearSelection(); - std::vector items; - items.push_back(mObjectID); - highlight_inventory_objects_in_panel(items, active_panel); - active_panel->getRootFolder()->scrollToShowSelection(); - - gInventory.removeObserver(this); - break; - } - } - } + LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); + + if (NULL == active_panel) + { + gInventory.removeObserver(this); + return; + } + + if((mask & (LLInventoryObserver::STRUCTURE)) != 0) + { + const std::set& changed_items = gInventory.getChangedIDs(); + + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + if ((*id_it) == mObjectID) + { + active_panel->clearSelection(); + std::vector items; + items.push_back(mObjectID); + highlight_inventory_objects_in_panel(items, active_panel); + active_panel->getRootFolder()->scrollToShowSelection(); + + gInventory.removeObserver(this); + break; + } + } + } } void set_dad_inbox_object(const LLUUID& object_id) { - LLViewerInventoryMoveObserver* move_observer = new LLViewerInventoryMoveObserver(object_id); - gInventory.addObserver(move_observer); + LLViewerInventoryMoveObserver* move_observer = new LLViewerInventoryMoveObserver(object_id); + gInventory.addObserver(move_observer); } -//unlike the FetchObserver for AgentOffer, we only make one +//unlike the FetchObserver for AgentOffer, we only make one //instance of the AddedObserver for TaskOffers -//and it never dies. We do this because we don't know the UUID of -//task offers until they are accepted, so we don't wouldn't +//and it never dies. We do this because we don't know the UUID of +//task offers until they are accepted, so we don't wouldn't //know what to watch for, so instead we just watch for all additions. class LLOpenTaskOffer : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() - { - uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) - { - added.push_back(*it); - } - for (uuid_vec_t::iterator it = added.begin(); it != added.end();) - { - const LLUUID& item_uuid = *it; - bool was_moved = false; - LLInventoryObject* added_object = gInventory.getObject(item_uuid); - if (added_object) - { - // cast to item to get Asset UUID - LLInventoryItem* added_item = dynamic_cast(added_object); - if (added_item) - { - const LLUUID& asset_uuid = added_item->getAssetUUID(); - if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) - { - LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; - was_moved = true; - } - } - } - - if (was_moved) - { - it = added.erase(it); - } - else ++it; - } - - open_inventory_offer(added, ""); - } + /*virtual*/ void done() + { + uuid_vec_t added; + for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + { + added.push_back(*it); + } + for (uuid_vec_t::iterator it = added.begin(); it != added.end();) + { + const LLUUID& item_uuid = *it; + bool was_moved = false; + LLInventoryObject* added_object = gInventory.getObject(item_uuid); + if (added_object) + { + // cast to item to get Asset UUID + LLInventoryItem* added_item = dynamic_cast(added_object); + if (added_item) + { + const LLUUID& asset_uuid = added_item->getAssetUUID(); + if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + was_moved = true; + } + } + } + + if (was_moved) + { + it = added.erase(it); + } + else ++it; + } + + open_inventory_offer(added, ""); + } }; class LLOpenTaskGroupOffer : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() - { - uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) - { - added.push_back(*it); - } - open_inventory_offer(added, "group_offer"); - gInventory.removeObserver(this); - delete this; - } + /*virtual*/ void done() + { + uuid_vec_t added; + for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + { + added.push_back(*it); + } + open_inventory_offer(added, "group_offer"); + gInventory.removeObserver(this); + delete this; + } }; //one global instance to bind them @@ -1281,267 +1281,267 @@ LLOpenTaskOffer* gNewInventoryObserver=NULL; class LLNewInventoryHintObserver : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() - { - LLFirstUse::newInventory(); - } + /*virtual*/ void done() + { + LLFirstUse::newInventory(); + } }; LLNewInventoryHintObserver* gNewInventoryHintObserver=NULL; void start_new_inventory_observer() { - if (!gNewInventoryObserver) //task offer observer - { - // Observer is deleted by gInventory - gNewInventoryObserver = new LLOpenTaskOffer; - gInventory.addObserver(gNewInventoryObserver); - } + if (!gNewInventoryObserver) //task offer observer + { + // Observer is deleted by gInventory + gNewInventoryObserver = new LLOpenTaskOffer; + gInventory.addObserver(gNewInventoryObserver); + } - if (!gInventoryMoveObserver) //inventory move from the world observer - { - // Observer is deleted by gInventory - gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; - gInventory.addObserver(gInventoryMoveObserver); - } + if (!gInventoryMoveObserver) //inventory move from the world observer + { + // Observer is deleted by gInventory + gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; + gInventory.addObserver(gInventoryMoveObserver); + } - if (!gNewInventoryHintObserver) - { - // Observer is deleted by gInventory - gNewInventoryHintObserver = new LLNewInventoryHintObserver(); - gInventory.addObserver(gNewInventoryHintObserver); - } + if (!gNewInventoryHintObserver) + { + // Observer is deleted by gInventory + gNewInventoryHintObserver = new LLNewInventoryHintObserver(); + gInventory.addObserver(gNewInventoryHintObserver); + } } class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver { - LOG_CLASS(LLDiscardAgentOffer); + LOG_CLASS(LLDiscardAgentOffer); public: - LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : - LLInventoryFetchItemsObserver(object_id), - mFolderID(folder_id), - mObjectID(object_id) {} - - virtual void done() - { - LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; - - // We're invoked from LLInventoryModel::notifyObservers(). - // If we now try to remove the inventory item, it will cause a nested - // notifyObservers() call, which won't work. - // So defer moving the item to trash until viewer gets idle (in a moment). - // Use removeObject() rather than removeItem() because at this level, - // the object could be either an item or a folder. - LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); - gInventory.removeObserver(this); - delete this; - } + LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : + LLInventoryFetchItemsObserver(object_id), + mFolderID(folder_id), + mObjectID(object_id) {} + + virtual void done() + { + LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; + + // We're invoked from LLInventoryModel::notifyObservers(). + // If we now try to remove the inventory item, it will cause a nested + // notifyObservers() call, which won't work. + // So defer moving the item to trash until viewer gets idle (in a moment). + // Use removeObject() rather than removeItem() because at this level, + // the object could be either an item or a folder. + LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); + gInventory.removeObserver(this); + delete this; + } protected: - LLUUID mFolderID; - LLUUID mObjectID; + LLUUID mFolderID; + LLUUID mObjectID; }; //Returns TRUE if we are OK, FALSE if we are throttled -//Set check_only true if you want to know the throttle status +//Set check_only true if you want to know the throttle status //without registering a hit bool check_offer_throttle(const std::string& from_name, bool check_only) { - static U32 throttle_count; - static bool throttle_logged; - LLChat chat; - std::string log_message; - - if (!gSavedSettings.getBOOL("ShowNewInventory")) - return false; - - if (check_only) - { - return gThrottleTimer.hasExpired(); - } - - if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) - { - LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; - throttle_count=1; - throttle_logged=false; - return true; - } - else //has not expired - { - LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; - // When downloading the initial inventory we get a lot of new items - // coming in and can't tell that from spam. - if (LLStartUp::getStartupState() >= STATE_STARTED - && throttle_count >= OFFER_THROTTLE_MAX_COUNT) - { - if (!throttle_logged) - { - // Use the name of the last item giver, who is probably the person - // spamming you. - - LLStringUtil::format_map_t arg; - std::string log_msg; - std::ostringstream time ; - time<getSecondLifeTitle(); - arg["TIME"] = time.str(); - - if (!from_name.empty()) - { - arg["FROM_NAME"] = from_name; - log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); - } - else - { - log_msg = LLTrans::getString("ItemsComingInTooFast", arg); - } - - //this is kinda important, so actually put it on screen - LLSD args; - args["MESSAGE"] = log_msg; - LLNotificationsUtil::add("SystemMessage", args); - - throttle_logged=true; - } - return false; - } - else - { - throttle_count++; - return true; - } - } -} - + static U32 throttle_count; + static bool throttle_logged; + LLChat chat; + std::string log_message; + + if (!gSavedSettings.getBOOL("ShowNewInventory")) + return false; + + if (check_only) + { + return gThrottleTimer.hasExpired(); + } + + if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) + { + LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; + throttle_count=1; + throttle_logged=false; + return true; + } + else //has not expired + { + LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; + // When downloading the initial inventory we get a lot of new items + // coming in and can't tell that from spam. + if (LLStartUp::getStartupState() >= STATE_STARTED + && throttle_count >= OFFER_THROTTLE_MAX_COUNT) + { + if (!throttle_logged) + { + // Use the name of the last item giver, who is probably the person + // spamming you. + + LLStringUtil::format_map_t arg; + std::string log_msg; + std::ostringstream time ; + time<getSecondLifeTitle(); + arg["TIME"] = time.str(); + + if (!from_name.empty()) + { + arg["FROM_NAME"] = from_name; + log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); + } + else + { + log_msg = LLTrans::getString("ItemsComingInTooFast", arg); + } + + //this is kinda important, so actually put it on screen + LLSD args; + args["MESSAGE"] = log_msg; + LLNotificationsUtil::add("SystemMessage", args); + + throttle_logged=true; + } + return false; + } + else + { + throttle_count++; + return true; + } + } +} + // Return "true" if we have a preview method for that asset type, "false" otherwise bool check_asset_previewable(const LLAssetType::EType asset_type) { - return (asset_type == LLAssetType::AT_NOTECARD) || - (asset_type == LLAssetType::AT_LANDMARK) || - (asset_type == LLAssetType::AT_TEXTURE) || - (asset_type == LLAssetType::AT_ANIMATION) || - (asset_type == LLAssetType::AT_SCRIPT) || - (asset_type == LLAssetType::AT_SOUND) || + return (asset_type == LLAssetType::AT_NOTECARD) || + (asset_type == LLAssetType::AT_LANDMARK) || + (asset_type == LLAssetType::AT_TEXTURE) || + (asset_type == LLAssetType::AT_ANIMATION) || + (asset_type == LLAssetType::AT_SCRIPT) || + (asset_type == LLAssetType::AT_SOUND) || (asset_type == LLAssetType::AT_MATERIAL); } void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) { - for (uuid_vec_t::const_iterator obj_iter = objects.begin(); - obj_iter != objects.end(); - ++obj_iter) - { - const LLUUID& obj_id = (*obj_iter); - if(!highlight_offered_object(obj_id)) - { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); - if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH)) - { - gInventory.checkTrashOverflow(); - } - continue; - } - - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) - { - LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; - continue; - } - - const LLAssetType::EType asset_type = obj->getActualType(); - - // Either an inventory item or a category. - const LLInventoryItem* item = dynamic_cast(obj); - if (item && check_asset_previewable(asset_type)) - { - //////////////////////////////////////////////////////////////////////////////// - // Special handling for various types. - if (check_offer_throttle(from_name, false)) // If we are throttled, don't display - { - LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL; - // If we opened this ourselves, focus it - const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; - switch(asset_type) - { - case LLAssetType::AT_NOTECARD: - { - LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus); - break; - } - case LLAssetType::AT_LANDMARK: - { - LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); - if ("inventory_handler" == from_name) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id", item->getUUID())); - } - else if("group_offer" == from_name) - { - // "group_offer" is passed by LLOpenTaskGroupOffer - // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done(). - LLSD args; - args["type"] = "landmark"; - args["id"] = obj_id; - LLFloaterSidePanelContainer::showPanel("places", args); - - continue; - } - else if(from_name.empty()) - { - std::string folder_name; - if (parent_folder) - { - // Localize folder name. - // *TODO: share this code? - folder_name = parent_folder->getName(); - if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType())) - { - LLTrans::findString(folder_name, "InvFolder " + folder_name); - } - } - else - { - folder_name = LLTrans::getString("Unknown"); - } - - // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. - LLSD args; - args["LANDMARK_NAME"] = item->getName(); - args["FOLDER_NAME"] = folder_name; - LLNotificationsUtil::add("LandmarkCreated", args); - } - } - break; - case LLAssetType::AT_TEXTURE: - { - LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus); - break; - } - case LLAssetType::AT_ANIMATION: - LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus); - break; - case LLAssetType::AT_SCRIPT: - LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus); - break; - case LLAssetType::AT_SOUND: - LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); - break; + for (uuid_vec_t::const_iterator obj_iter = objects.begin(); + obj_iter != objects.end(); + ++obj_iter) + { + const LLUUID& obj_id = (*obj_iter); + if(!highlight_offered_object(obj_id)) + { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH)) + { + gInventory.checkTrashOverflow(); + } + continue; + } + + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (!obj) + { + LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; + continue; + } + + const LLAssetType::EType asset_type = obj->getActualType(); + + // Either an inventory item or a category. + const LLInventoryItem* item = dynamic_cast(obj); + if (item && check_asset_previewable(asset_type)) + { + //////////////////////////////////////////////////////////////////////////////// + // Special handling for various types. + if (check_offer_throttle(from_name, false)) // If we are throttled, don't display + { + LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL; + // If we opened this ourselves, focus it + const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; + switch(asset_type) + { + case LLAssetType::AT_NOTECARD: + { + LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus); + break; + } + case LLAssetType::AT_LANDMARK: + { + LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); + if ("inventory_handler" == from_name) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id", item->getUUID())); + } + else if("group_offer" == from_name) + { + // "group_offer" is passed by LLOpenTaskGroupOffer + // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done(). + LLSD args; + args["type"] = "landmark"; + args["id"] = obj_id; + LLFloaterSidePanelContainer::showPanel("places", args); + + continue; + } + else if(from_name.empty()) + { + std::string folder_name; + if (parent_folder) + { + // Localize folder name. + // *TODO: share this code? + folder_name = parent_folder->getName(); + if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType())) + { + LLTrans::findString(folder_name, "InvFolder " + folder_name); + } + } + else + { + folder_name = LLTrans::getString("Unknown"); + } + + // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. + LLSD args; + args["LANDMARK_NAME"] = item->getName(); + args["FOLDER_NAME"] = folder_name; + LLNotificationsUtil::add("LandmarkCreated", args); + } + } + break; + case LLAssetType::AT_TEXTURE: + { + LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus); + break; + } + case LLAssetType::AT_ANIMATION: + LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus); + break; + case LLAssetType::AT_SCRIPT: + LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus); + break; + case LLAssetType::AT_SOUND: + LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); + break; case LLAssetType::AT_MATERIAL: // Explicitly do nothing -- we don't want to open the material editor every time you add a material to inventory break; - default: - LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL; - break; - } - } - } - - //////////////////////////////////////////////////////////////////////////////// + default: + LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL; + break; + } + } + } + + //////////////////////////////////////////////////////////////////////////////// static LLUICachedControl find_original_new_floater("FindOriginalOpenWindow", false); //show in a new single-folder window if(find_original_new_floater && !from_name.empty()) @@ -1578,34 +1578,34 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam LLInventoryPanel::openInventoryPanelAndSetSelection(auto_open, obj_id, use_main_panel); } - } + } } bool highlight_offered_object(const LLUUID& obj_id) { - const LLInventoryObject* obj = gInventory.getObject(obj_id); - if(!obj) - { - LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; - return false; - } - - //////////////////////////////////////////////////////////////////////////////// - // Don't highlight if it's in certain "quiet" folders which don't need UI - // notification (e.g. trash, cof, lost-and-found). - if(!gAgent.getAFK()) - { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); - if (parent) - { - const LLFolderType::EType parent_type = parent->getPreferredType(); - if (LLViewerFolderType::lookupIsQuietType(parent_type)) - { - return false; - } - } - } - + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if(!obj) + { + LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; + return false; + } + + //////////////////////////////////////////////////////////////////////////////// + // Don't highlight if it's in certain "quiet" folders which don't need UI + // notification (e.g. trash, cof, lost-and-found). + if(!gAgent.getAFK()) + { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent) + { + const LLFolderType::EType parent_type = parent->getPreferredType(); + if (LLViewerFolderType::lookupIsQuietType(parent_type)) + { + return false; + } + } + } + if (obj->getType() == LLAssetType::AT_LANDMARK) { LLFloaterCreateLandmark *floater = LLFloaterReg::findTypedInstance("add_landmark"); @@ -1617,43 +1617,43 @@ bool highlight_offered_object(const LLUUID& obj_id) } } - return true; + return true; } void inventory_offer_mute_callback(const LLUUID& blocked_id, - const std::string& full_name, - bool is_group) -{ - // *NOTE: blocks owner if the offer came from an object - LLMute::EType mute_type = is_group ? LLMute::GROUP : LLMute::AGENT; - - LLMute mute(blocked_id, full_name, mute_type); - if (LLMuteList::getInstance()->add(mute)) - { - LLPanelBlockedList::showPanelAndSelect(blocked_id); - } - - // purge the message queue of any previously queued inventory offers from the same source. - class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher - { - public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const - { - if(notification->getName() == "ObjectGiveItem" - || notification->getName() == "OwnObjectGiveItem" - || notification->getName() == "UserGiveItem") - { - return (notification->getPayload()["from_id"].asUUID() == blocked_id); - } - return FALSE; - } - private: - const LLUUID& blocked_id; - }; - - LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( - gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); + const std::string& full_name, + bool is_group) +{ + // *NOTE: blocks owner if the offer came from an object + LLMute::EType mute_type = is_group ? LLMute::GROUP : LLMute::AGENT; + + LLMute mute(blocked_id, full_name, mute_type); + if (LLMuteList::getInstance()->add(mute)) + { + LLPanelBlockedList::showPanelAndSelect(blocked_id); + } + + // purge the message queue of any previously queued inventory offers from the same source. + class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher + { + public: + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} + bool matches(const LLNotificationPtr notification) const + { + if(notification->getName() == "ObjectGiveItem" + || notification->getName() == "OwnObjectGiveItem" + || notification->getName() == "UserGiveItem") + { + return (notification->getPayload()["from_id"].asUUID() == blocked_id); + } + return FALSE; + } + private: + const LLUUID& blocked_id; + }; + + LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( + gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); } @@ -1678,602 +1678,602 @@ LLOfferInfo::LLOfferInfo() LLOfferInfo::LLOfferInfo(const LLSD& sd) { - mIM = (EInstantMessage)sd["im_type"].asInteger(); - mFromID = sd["from_id"].asUUID(); - mFromGroup = sd["from_group"].asBoolean(); - mFromObject = sd["from_object"].asBoolean(); - mTransactionID = sd["transaction_id"].asUUID(); - mFolderID = sd["folder_id"].asUUID(); - mObjectID = sd["object_id"].asUUID(); - mType = LLAssetType::lookup(sd["type"].asString().c_str()); - mFromName = sd["from_name"].asString(); - mDesc = sd["description"].asString(); - mHost = LLHost(sd["sender"].asString()); - mPersist = sd["persist"].asBoolean(); + mIM = (EInstantMessage)sd["im_type"].asInteger(); + mFromID = sd["from_id"].asUUID(); + mFromGroup = sd["from_group"].asBoolean(); + mFromObject = sd["from_object"].asBoolean(); + mTransactionID = sd["transaction_id"].asUUID(); + mFolderID = sd["folder_id"].asUUID(); + mObjectID = sd["object_id"].asUUID(); + mType = LLAssetType::lookup(sd["type"].asString().c_str()); + mFromName = sd["from_name"].asString(); + mDesc = sd["description"].asString(); + mHost = LLHost(sd["sender"].asString()); + mPersist = sd["persist"].asBoolean(); } LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) { - mIM = info.mIM; - mFromID = info.mFromID; - mFromGroup = info.mFromGroup; - mFromObject = info.mFromObject; - mTransactionID = info.mTransactionID; - mFolderID = info.mFolderID; - mObjectID = info.mObjectID; - mType = info.mType; - mFromName = info.mFromName; - mDesc = info.mDesc; - mHost = info.mHost; - mPersist = info.mPersist; + mIM = info.mIM; + mFromID = info.mFromID; + mFromGroup = info.mFromGroup; + mFromObject = info.mFromObject; + mTransactionID = info.mTransactionID; + mFolderID = info.mFolderID; + mObjectID = info.mObjectID; + mType = info.mType; + mFromName = info.mFromName; + mDesc = info.mDesc; + mHost = info.mHost; + mPersist = info.mPersist; } LLSD LLOfferInfo::asLLSD() { - LLSD sd; + LLSD sd; sd["responder_type"] = mResponderType; - sd["im_type"] = mIM; - sd["from_id"] = mFromID; - sd["from_group"] = mFromGroup; - sd["from_object"] = mFromObject; - sd["transaction_id"] = mTransactionID; - sd["folder_id"] = mFolderID; - sd["object_id"] = mObjectID; - sd["type"] = LLAssetType::lookup(mType); - sd["from_name"] = mFromName; - sd["description"] = mDesc; - sd["sender"] = mHost.getIPandPort(); - sd["persist"] = mPersist; - return sd; + sd["im_type"] = mIM; + sd["from_id"] = mFromID; + sd["from_group"] = mFromGroup; + sd["from_object"] = mFromObject; + sd["transaction_id"] = mTransactionID; + sd["folder_id"] = mFolderID; + sd["object_id"] = mObjectID; + sd["type"] = LLAssetType::lookup(mType); + sd["from_name"] = mFromName; + sd["description"] = mDesc; + sd["sender"] = mHost.getIPandPort(); + sd["persist"] = mPersist; + return sd; } void LLOfferInfo::fromLLSD(const LLSD& params) { - *this = params; + *this = params; } void LLOfferInfo::sendReceiveResponse(bool accept, const LLUUID &destination_folder_id) { - if(IM_INVENTORY_OFFERED == mIM) - { - // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); - } - - if (mTransactionID.isNull()) - { - // Not provided, message won't work - return; - } - - 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, mFromID); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, mTransactionID); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, ""); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - - // ACCEPT. The math for the dialog works, because the accept - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 1 greater than the offer integer value. - // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, - // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - // Decline for inventory_offered, task_inventory_offer or - // group_notice_inventory is 2 greater than the offer integer value. - - EInstantMessage im = mIM; - if (mIM == IM_GROUP_NOTICE_REQUESTED) - { - // Request has no responder dialogs - im = IM_GROUP_NOTICE; - } - - if (accept) - { - msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(destination_folder_id.mData), - sizeof(destination_folder_id.mData)); - } - else - { - msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 2)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); - } - // send the message - msg->sendReliable(mHost); - - // transaction id is usable only once - // Note: a bit of a hack, clicking group notice attachment will not close notice - // so we reset no longer usable transaction id to know not to send message again - // Once capabilities for responses will be implemented LLOfferInfo will have to - // remember that it already responded in another way and ignore IOR_DECLINE - mTransactionID.setNull(); + if(IM_INVENTORY_OFFERED == mIM) + { + // add buddy to recent people list + LLRecentPeople::instance().add(mFromID); + } + + if (mTransactionID.isNull()) + { + // Not provided, message won't work + return; + } + + 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, mFromID); + msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); + msg->addUUIDFast(_PREHASH_ID, mTransactionID); + msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary + std::string name; + LLAgentUI::buildFullname(name); + msg->addStringFast(_PREHASH_FromAgentName, name); + msg->addStringFast(_PREHASH_Message, ""); + msg->addU32Fast(_PREHASH_ParentEstateID, 0); + msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); + msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); + + // ACCEPT. The math for the dialog works, because the accept + // for inventory_offered, task_inventory_offer or + // group_notice_inventory is 1 greater than the offer integer value. + // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, + // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED + // Decline for inventory_offered, task_inventory_offer or + // group_notice_inventory is 2 greater than the offer integer value. + + EInstantMessage im = mIM; + if (mIM == IM_GROUP_NOTICE_REQUESTED) + { + // Request has no responder dialogs + im = IM_GROUP_NOTICE; + } + + if (accept) + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 1)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(destination_folder_id.mData), + sizeof(destination_folder_id.mData)); + } + else + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 2)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); + } + // send the message + msg->sendReliable(mHost); + + // transaction id is usable only once + // Note: a bit of a hack, clicking group notice attachment will not close notice + // so we reset no longer usable transaction id to know not to send message again + // Once capabilities for responses will be implemented LLOfferInfo will have to + // remember that it already responded in another way and ignore IOR_DECLINE + mTransactionID.setNull(); } void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response) { - initRespondFunctionMap(); + initRespondFunctionMap(); - const std::string name = notification["name"].asString(); - if(mRespondFunctions.find(name) == mRespondFunctions.end()) - { - LL_WARNS() << "Unexpected notification name : " << name << LL_ENDL; - llassert(!"Unexpected notification name"); - return; - } + const std::string name = notification["name"].asString(); + if(mRespondFunctions.find(name) == mRespondFunctions.end()) + { + LL_WARNS() << "Unexpected notification name : " << name << LL_ENDL; + llassert(!"Unexpected notification name"); + return; + } - mRespondFunctions[name](notification, response); + mRespondFunctions[name](notification, response); } bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response) { - LLChat chat; - std::string log_message; - S32 button = LLNotificationsUtil::getSelectedOption(notification, response); - - LLInventoryObserver* opener = NULL; - LLViewerInventoryCategory* catp = NULL; - catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); - LLViewerInventoryItem* itemp = NULL; - if(!catp) - { - itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); - } - - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - // For muting, we need to add the mute, then decline the offer. - // This must be done here because: - // * callback may be called immediately, - // * adding the mute sends a message, - // * we can't build two messages at once. - if (IOR_MUTE == button) // Block - { - if (notification_ptr != NULL) - { - if (mFromGroup) - { - gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); - } - else - { - LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); - } - } - } - - std::string from_string; // Used in the pop-up. - std::string chatHistory_string; // Used in chat history. - - // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: - from_string = chatHistory_string = mFromName; - - // accept goes to proper folder, decline gets accepted to trash, muted gets declined - bool accept_to_trash = true; - - LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); - - switch(button) - { - case IOR_SHOW: - // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID - << LL_ENDL; - switch (mIM) - { - case IM_INVENTORY_OFFERED: - { - // This is an offer from an agent. In this case, the back - // end has already copied the items into your inventory, - // so we can fetch it out of our inventory. - if (gSavedSettings.getBOOL("ShowOfferedInventory")) - { - LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); - open_agent_offer->startFetch(); - if(catp || (itemp && itemp->isFinished())) - { - open_agent_offer->done(); - } - else - { - opener = open_agent_offer; - } - } - } - break; - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - opener = new LLOpenTaskGroupOffer; - sendReceiveResponse(true, mFolderID); - break; - case IM_TASK_INVENTORY_OFFERED: - // This is an offer from a task or group. - // We don't use a new instance of an opener - // We instead use the singular observer gOpenTaskOffer - // Since it already exists, we don't need to actually do anything - break; - default: - LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; - break; - } - - if (modified_form != NULL) - { - modified_form->setElementEnabled("Show", false); - } - break; - // end switch (mIM) - - case IOR_ACCEPT: - //don't spam them if they are getting flooded - if (check_offer_throttle(mFromName, true)) - { - log_message = "" + chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - - break; - - case IOR_MUTE: - if (modified_form != NULL) - { - modified_form->setElementEnabled("Mute", false); - } - accept_to_trash = false; // for notices, but IOR_MUTE normally doesn't happen for notices - // MUTE falls through to decline - case IOR_DECLINE: - { - { - LLStringUtil::format_map_t log_message_args; - log_message_args["DESC"] = mDesc; - log_message_args["NAME"] = mFromName; - log_message = LLTrans::getString("InvOfferDecline", log_message_args); - } - chat.mText = log_message; - if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::isLinden(mFromName) ) // muting for SL-42269 - { - chat.mMuted = TRUE; - accept_to_trash = false; // will send decline message - } - - // *NOTE dzaporozhan - // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 - // LLFloaterChat::addChatHistory(chat); - - if (mObjectID.notNull()) //make sure we can discard - { - LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->startFetch(); - if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) - { - discard_agent_offer->done(); - } - else - { - opener = discard_agent_offer; - } - } - else if (mIM == IM_GROUP_NOTICE) - { - // group notice needs to request object to trash so that user will see it later - // Note: muted agent offers go to trash, not sure if we should do same for notices - LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - sendReceiveResponse(accept_to_trash, trash); - } - - if (modified_form != NULL) - { - modified_form->setElementEnabled("Show", false); - modified_form->setElementEnabled("Discard", false); - } - - break; - } - default: - // close button probably - // In case of agent offers item has already been fetched and is in your inventory, we simply won't highlight it - // OR delete it if the notification gets killed, since we don't want that to be a vector for - // losing inventory offers. - if (mIM == IM_GROUP_NOTICE) - { - LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - sendReceiveResponse(true, trash); - } - break; - } - - if(opener) - { - gInventory.addObserver(opener); - } - - if(!mPersist) - { - delete this; - } - - return false; + LLChat chat; + std::string log_message; + S32 button = LLNotificationsUtil::getSelectedOption(notification, response); + + LLInventoryObserver* opener = NULL; + LLViewerInventoryCategory* catp = NULL; + catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); + LLViewerInventoryItem* itemp = NULL; + if(!catp) + { + itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); + } + + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + // For muting, we need to add the mute, then decline the offer. + // This must be done here because: + // * callback may be called immediately, + // * adding the mute sends a message, + // * we can't build two messages at once. + if (IOR_MUTE == button) // Block + { + if (notification_ptr != NULL) + { + if (mFromGroup) + { + gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); + } + } + } + + std::string from_string; // Used in the pop-up. + std::string chatHistory_string; // Used in chat history. + + // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: + from_string = chatHistory_string = mFromName; + + // accept goes to proper folder, decline gets accepted to trash, muted gets declined + bool accept_to_trash = true; + + LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); + + switch(button) + { + case IOR_SHOW: + // we will want to open this item when it comes back. + LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID + << LL_ENDL; + switch (mIM) + { + case IM_INVENTORY_OFFERED: + { + // This is an offer from an agent. In this case, the back + // end has already copied the items into your inventory, + // so we can fetch it out of our inventory. + if (gSavedSettings.getBOOL("ShowOfferedInventory")) + { + LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); + open_agent_offer->startFetch(); + if(catp || (itemp && itemp->isFinished())) + { + open_agent_offer->done(); + } + else + { + opener = open_agent_offer; + } + } + } + break; + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: + opener = new LLOpenTaskGroupOffer; + sendReceiveResponse(true, mFolderID); + break; + case IM_TASK_INVENTORY_OFFERED: + // This is an offer from a task or group. + // We don't use a new instance of an opener + // We instead use the singular observer gOpenTaskOffer + // Since it already exists, we don't need to actually do anything + break; + default: + LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; + break; + } + + if (modified_form != NULL) + { + modified_form->setElementEnabled("Show", false); + } + break; + // end switch (mIM) + + case IOR_ACCEPT: + //don't spam them if they are getting flooded + if (check_offer_throttle(mFromName, true)) + { + log_message = "" + chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + + break; + + case IOR_MUTE: + if (modified_form != NULL) + { + modified_form->setElementEnabled("Mute", false); + } + accept_to_trash = false; // for notices, but IOR_MUTE normally doesn't happen for notices + // MUTE falls through to decline + case IOR_DECLINE: + { + { + LLStringUtil::format_map_t log_message_args; + log_message_args["DESC"] = mDesc; + log_message_args["NAME"] = mFromName; + log_message = LLTrans::getString("InvOfferDecline", log_message_args); + } + chat.mText = log_message; + if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::isLinden(mFromName) ) // muting for SL-42269 + { + chat.mMuted = TRUE; + accept_to_trash = false; // will send decline message + } + + // *NOTE dzaporozhan + // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 + // LLFloaterChat::addChatHistory(chat); + + if (mObjectID.notNull()) //make sure we can discard + { + LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); + discard_agent_offer->startFetch(); + if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) + { + discard_agent_offer->done(); + } + else + { + opener = discard_agent_offer; + } + } + else if (mIM == IM_GROUP_NOTICE) + { + // group notice needs to request object to trash so that user will see it later + // Note: muted agent offers go to trash, not sure if we should do same for notices + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(accept_to_trash, trash); + } + + if (modified_form != NULL) + { + modified_form->setElementEnabled("Show", false); + modified_form->setElementEnabled("Discard", false); + } + + break; + } + default: + // close button probably + // In case of agent offers item has already been fetched and is in your inventory, we simply won't highlight it + // OR delete it if the notification gets killed, since we don't want that to be a vector for + // losing inventory offers. + if (mIM == IM_GROUP_NOTICE) + { + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(true, trash); + } + break; + } + + if(opener) + { + gInventory.addObserver(opener); + } + + if(!mPersist) + { + delete this; + } + + return false; } bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response) { - LLChat chat; - std::string log_message; - S32 button = LLNotification::getSelectedOption(notification, response); - - // For muting, we need to add the mute, then decline the offer. - // This must be done here because: - // * callback may be called immediately, - // * adding the mute sends a message, - // * we can't build two messages at once. - if (2 == button) - { - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - llassert(notification_ptr != NULL); - if (notification_ptr != NULL) - { - if (mFromGroup) - { - gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); - } - else - { - LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); - } - } - } - - std::string from_string; // Used in the pop-up. - std::string chatHistory_string; // Used in chat history. - - if (mFromObject == TRUE) - { - if (mFromGroup) - { - std::string group_name; - if (gCacheName->getGroupName(mFromID, group_name)) - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" - + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") - + " "+ "'" + group_name + "'"; - - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") - + " " + group_name + "'"; - } - else - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" - + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); - } - } - else - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(mFromID, &av_name)) - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName - + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + av_name.getUserName(); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + av_name.getUserName(); - } - else - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") - + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - } - } - } - else - { - from_string = chatHistory_string = mFromName; - } - - LLUUID destination; - bool accept = true; - - // If user accepted, accept to proper folder, if user discarded, accept to trash. - switch(button) - { - case IOR_ACCEPT: - destination = mFolderID; - //don't spam user if flooded - if (check_offer_throttle(mFromName, true)) - { - log_message = "" + chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - break; - case IOR_MUTE: - // MUTE falls through to decline - accept = false; - case IOR_DECLINE: - default: - // close button probably (or any of the fall-throughs from above) - destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (accept && LLMuteList::getInstance()->isMuted(mFromID, mFromName)) - { - // Note: muted offers are usually declined automatically, - // but user can mute object after receiving message - accept = false; - } - break; - } - - sendReceiveResponse(accept, destination); - - if(!mPersist) - { - delete this; - } - return false; + LLChat chat; + std::string log_message; + S32 button = LLNotification::getSelectedOption(notification, response); + + // For muting, we need to add the mute, then decline the offer. + // This must be done here because: + // * callback may be called immediately, + // * adding the mute sends a message, + // * we can't build two messages at once. + if (2 == button) + { + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + llassert(notification_ptr != NULL); + if (notification_ptr != NULL) + { + if (mFromGroup) + { + gCacheName->getGroup(mFromID, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(mFromID, boost::bind(&inventory_offer_mute_avatar_callback, _1, _2)); + } + } + } + + std::string from_string; // Used in the pop-up. + std::string chatHistory_string; // Used in chat history. + + if (mFromObject == TRUE) + { + if (mFromGroup) + { + std::string group_name; + if (gCacheName->getGroupName(mFromID, group_name)) + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" + + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") + + " "+ "'" + group_name + "'"; + + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") + + " " + group_name + "'"; + } + else + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" + + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); + } + } + else + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(mFromID, &av_name)) + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName + + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + av_name.getUserName(); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + av_name.getUserName(); + } + else + { + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") + + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); + } + } + } + else + { + from_string = chatHistory_string = mFromName; + } + + LLUUID destination; + bool accept = true; + + // If user accepted, accept to proper folder, if user discarded, accept to trash. + switch(button) + { + case IOR_ACCEPT: + destination = mFolderID; + //don't spam user if flooded + if (check_offer_throttle(mFromName, true)) + { + log_message = "" + chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + break; + case IOR_MUTE: + // MUTE falls through to decline + accept = false; + case IOR_DECLINE: + default: + // close button probably (or any of the fall-throughs from above) + destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (accept && LLMuteList::getInstance()->isMuted(mFromID, mFromName)) + { + // Note: muted offers are usually declined automatically, + // but user can mute object after receiving message + accept = false; + } + break; + } + + sendReceiveResponse(accept, destination); + + if(!mPersist) + { + delete this; + } + return false; } std::string LLOfferInfo::getSanitizedDescription() { - // currently we get description from server as: 'Object' ( Location ) - // object name shouldn't be shown as a hyperlink - std::string description = mDesc; + // currently we get description from server as: 'Object' ( Location ) + // object name shouldn't be shown as a hyperlink + std::string description = mDesc; - std::size_t start = mDesc.find_first_of("'"); - std::size_t end = mDesc.find_last_of("'"); - if ((start != std::string::npos) && (end != std::string::npos)) - { - description.insert(start, ""); - description.insert(end + 8, ""); - } - return description; + std::size_t start = mDesc.find_first_of("'"); + std::size_t end = mDesc.find_last_of("'"); + if ((start != std::string::npos) && (end != std::string::npos)) + { + description.insert(start, ""); + description.insert(end + 8, ""); + } + return description; } void LLOfferInfo::initRespondFunctionMap() { - if(mRespondFunctions.empty()) - { - mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); - mRespondFunctions["OwnObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); - mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2); - } + if(mRespondFunctions.empty()) + { + mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); + mRespondFunctions["OwnObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); + mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2); + } } bool lure_callback(const LLSD& notification, const LLSD& response) { - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); - BOOL godlike = notification["payload"]["godlike"].asBoolean(); - - switch(option) - { - case 0: - { - // accept - gAgent.teleportViaLure(lure_id, godlike); - } - break; - case 1: - default: - // decline - send_simple_im(from_id, - LLStringUtil::null, - IM_LURE_DECLINED, - lure_id); - break; - } - - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - if (notification_ptr) - { - LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); - modified_form->setElementEnabled("Teleport", false); - modified_form->setElementEnabled("Cancel", false); - notification_ptr->updateForm(modified_form); - notification_ptr->repost(); - } - - return false; + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); + + switch(option) + { + case 0: + { + // accept + gAgent.teleportViaLure(lure_id, godlike); + } + break; + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); + break; + } + + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + if (notification_ptr) + { + LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + modified_form->setElementEnabled("Teleport", false); + modified_form->setElementEnabled("Cancel", false); + notification_ptr->updateForm(modified_form); + notification_ptr->repost(); + } + + return false; } static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); bool mature_lure_callback(const LLSD& notification, const LLSD& response) { - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); - BOOL godlike = notification["payload"]["godlike"].asBoolean(); - U8 region_access = static_cast(notification["payload"]["region_maturity"].asInteger()); - - switch(option) - { - case 0: - { - // accept - gSavedSettings.setU32("PreferredMaturity", static_cast(region_access)); - gAgent.setMaturityRatingChangeDuringTeleport(region_access); - gAgent.teleportViaLure(lure_id, godlike); - } - break; - case 1: - default: - // decline - send_simple_im(from_id, - LLStringUtil::null, - IM_LURE_DECLINED, - lure_id); - break; - } - return false; + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); + U8 region_access = static_cast(notification["payload"]["region_maturity"].asInteger()); + + switch(option) + { + case 0: + { + // accept + gSavedSettings.setU32("PreferredMaturity", static_cast(region_access)); + gAgent.setMaturityRatingChangeDuringTeleport(region_access); + gAgent.teleportViaLure(lure_id, godlike); + } + break; + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); + break; + } + return false; } static LLNotificationFunctorRegistration mature_lure_callback_reg("TeleportOffered_MaturityExceeded", mature_lure_callback); bool goto_url_callback(const LLSD& notification, const LLSD& response) { - std::string url = notification["payload"]["url"].asString(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(1 == option) - { - LLWeb::loadURL(url); - } - return false; + std::string url = notification["payload"]["url"].asString(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(1 == option) + { + LLWeb::loadURL(url); + } + return false; } static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]); - } - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]); + } + return false; } static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback); class LLPostponedServerObjectNotification: public LLPostponedNotification { protected: - /* virtual */ - void modifyNotificationParams() - { - LLSD payload = mParams.payload; - mParams.payload = payload; - } + /* virtual */ + void modifyNotificationParams() + { + LLSD payload = mParams.payload; + mParams.payload = payload; + } }; void process_improved_im(LLMessageSystem *msg, void **user_data) @@ -2303,7 +2303,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, d); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); - //msg->getData("MessageBlock", "Count", &count); + //msg->getData("MessageBlock", "Count", &count); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, agentName); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); @@ -2333,129 +2333,129 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) void send_do_not_disturb_message (LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) { - if (gAgent.isDoNotDisturb()) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response = gSavedPerAccountSettings.getString("DoNotDisturbModeResponse"); - pack_instant_message( - msg, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - response, - IM_ONLINE, - IM_DO_NOT_DISTURB_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - } + if (gAgent.isDoNotDisturb()) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response = gSavedPerAccountSettings.getString("DoNotDisturbModeResponse"); + pack_instant_message( + msg, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + from_id, + my_name, + response, + IM_ONLINE, + IM_DO_NOT_DISTURB_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + } } bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLUUID fid; - LLUUID from_id; - LLMessageSystem* msg = gMessageSystem; - switch(option) - { - case 0: - // accept - msg->newMessageFast(_PREHASH_AcceptCallingCard); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - break; - case 1: - // decline - msg->newMessageFast(_PREHASH_DeclineCallingCard); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - send_do_not_disturb_message(msg, notification["payload"]["source_id"].asUUID()); - break; - default: - // close button probably, possibly timed out - break; - } - - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLUUID fid; + LLUUID from_id; + LLMessageSystem* msg = gMessageSystem; + switch(option) + { + case 0: + // accept + msg->newMessageFast(_PREHASH_AcceptCallingCard); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); + fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + break; + case 1: + // decline + msg->newMessageFast(_PREHASH_DeclineCallingCard); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + send_do_not_disturb_message(msg, notification["payload"]["source_id"].asUUID()); + break; + default: + // close button probably, possibly timed out + break; + } + + return false; } static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); void process_offer_callingcard(LLMessageSystem* msg, void**) { - // someone has offered to form a friendship - LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL; - - LLUUID source_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); - LLUUID tid; - msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid); - - LLSD payload; - payload["transaction_id"] = tid; - payload["source_id"] = source_id; - payload["sender"] = msg->getSender().getIPandPort(); - - LLViewerObject* source = gObjectList.findObject(source_id); - LLSD args; - std::string source_name; - if(source && source->isAvatar()) - { - LLNameValue* nvfirst = source->getNVPair("FirstName"); - LLNameValue* nvlast = source->getNVPair("LastName"); - if (nvfirst && nvlast) - { - source_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - } - - if(!source_name.empty()) - { - if (gAgent.isDoNotDisturb() - || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) - { - // automatically decline offer - LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1); - } - else - { - args["NAME"] = source_name; - LLNotificationsUtil::add("OfferCallingCard", args, payload); - } - } - else - { - LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL; - } + // someone has offered to form a friendship + LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL; + + LLUUID source_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); + LLUUID tid; + msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid); + + LLSD payload; + payload["transaction_id"] = tid; + payload["source_id"] = source_id; + payload["sender"] = msg->getSender().getIPandPort(); + + LLViewerObject* source = gObjectList.findObject(source_id); + LLSD args; + std::string source_name; + if(source && source->isAvatar()) + { + LLNameValue* nvfirst = source->getNVPair("FirstName"); + LLNameValue* nvlast = source->getNVPair("LastName"); + if (nvfirst && nvlast) + { + source_name = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + } + } + + if(!source_name.empty()) + { + if (gAgent.isDoNotDisturb() + || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) + { + // automatically decline offer + LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1); + } + else + { + args["NAME"] = source_name; + LLNotificationsUtil::add("OfferCallingCard", args, payload); + } + } + else + { + LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL; + } } void process_accept_callingcard(LLMessageSystem* msg, void**) { - LLNotificationsUtil::add("CallingCardAccepted"); + LLNotificationsUtil::add("CallingCardAccepted"); } void process_decline_callingcard(LLMessageSystem* msg, void**) { - LLNotificationsUtil::add("CallingCardDeclined"); + LLNotificationsUtil::add("CallingCardDeclined"); } void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std::string expectLang, std::string translation, const std::string detected_language) { - // filter out non-interesting responses + // filter out non-interesting responses if (!translation.empty() && ((detected_language.empty()) || (expectLang != detected_language)) && (LLStringUtil::compareInsensitive(translation, originalMsg) != 0)) @@ -2463,7 +2463,7 @@ void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std: chat.mText += " (" + LLTranslate::removeNoTranslateTags(translation) + ")"; } - LLTranslate::instance().logSuccess(1); + LLTranslate::instance().logSuccess(1); LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs); } @@ -2473,424 +2473,424 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages chat.mText += " (" + msg + ")"; - LLTranslate::instance().logFailure(1); + LLTranslate::instance().logFailure(1); LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs); } void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { - if (gNonInteractive) - { - return; - } - LLChat chat; - std::string mesg; - std::string from_name; - U8 source_temp; - U8 type_temp; - U8 audible_temp; - LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f); - LLUUID from_id; - LLUUID owner_id; - LLViewerObject* chatter; - - msg->getString("ChatData", "FromName", from_name); - - msg->getUUID("ChatData", "SourceID", from_id); - chat.mFromID = from_id; - - // Object owner for objects - msg->getUUID("ChatData", "OwnerID", owner_id); - - msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); - chat.mSourceType = (EChatSourceType)source_temp; - - msg->getU8("ChatData", "ChatType", type_temp); - chat.mChatType = (EChatType)type_temp; - - msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp); - chat.mAudible = (EChatAudible)audible_temp; - - chat.mTime = LLFrameTimer::getElapsedSeconds(); - - // IDEVO Correct for new-style "Resident" names - if (chat.mSourceType == CHAT_SOURCE_AGENT) - { - // I don't know if it's OK to change this here, if - // anything downstream does lookups by name, for instance - - LLAvatarName av_name; - if (LLAvatarNameCache::get(from_id, &av_name)) - { - chat.mFromName = av_name.getCompleteName(); - } - else - { - chat.mFromName = LLCacheName::cleanFullName(from_name); - } - } - else - { - // make sure that we don't have an empty or all-whitespace name - LLStringUtil::trim(from_name); - if (from_name.empty()) - { - from_name = LLTrans::getString("Unnamed"); - } - chat.mFromName = from_name; - } - - BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - - BOOL is_muted = FALSE; - BOOL is_linden = FALSE; - is_muted = LLMuteList::getInstance()->isMuted( - from_id, - from_name, - LLMute::flagTextChat) - || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat); - is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && - LLMuteList::isLinden(from_name); - - if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) - { - return; - } - - BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); - chatter = gObjectList.findObject(from_id); - if (chatter) - { - chat.mPosAgent = chatter->getPositionAgent(); - - // Make swirly things only for talking objects. (not script debug messages, though) - if (chat.mSourceType == CHAT_SOURCE_OBJECT - && chat.mChatType != CHAT_TYPE_DEBUG_MSG - && gSavedSettings.getBOOL("EffectScriptChatParticles") ) - { - LLPointer psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); - psc->setSourceObject(chatter); - psc->setColor(color); - //We set the particles to be owned by the object's owner, - //just in case they should be muted by the mute list - psc->setOwnerUUID(owner_id); - LLViewerPartSim::getInstance()->addPartSource(psc); - } - - // record last audible utterance - if (is_audible - && (is_linden || (!is_muted && !is_do_not_disturb))) - { - if (chat.mChatType != CHAT_TYPE_START - && chat.mChatType != CHAT_TYPE_STOP) - { - gAgent.heardChat(chat.mFromID); - } - } - } - - if (is_audible) - { - //BOOL visible_in_chat_bubble = FALSE; - - color.setVec(1.f,1.f,1.f,1.f); - msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); - - BOOL ircstyle = FALSE; - - // Look for IRC-style emotes here so chatbubbles work - std::string prefix = mesg.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - ircstyle = TRUE; - } - chat.mText = mesg; - - // Look for the start of typing so we can put "..." in the bubbles. - if (CHAT_TYPE_START == chat.mChatType) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE); - - // Might not have the avatar constructed yet, eg on login. - if (chatter && chatter->isAvatar()) - { - ((LLVOAvatar*)chatter)->startTyping(); - } - return; - } - else if (CHAT_TYPE_STOP == chat.mChatType) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - - // Might not have the avatar constructed yet, eg on login. - if (chatter && chatter->isAvatar()) - { - ((LLVOAvatar*)chatter)->stopTyping(); - } - return; - } - - // Look for IRC-style emotes - if (ircstyle) - { - // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656 - chat.mChatStyle = CHAT_STYLE_IRC; - - // Do nothing, ircstyle is fixed above for chat bubbles - } - else - { - chat.mText = ""; - switch(chat.mChatType) - { - case CHAT_TYPE_WHISPER: - chat.mText = LLTrans::getString("whisper") + " "; - break; - case CHAT_TYPE_DEBUG_MSG: - case CHAT_TYPE_OWNER: - case CHAT_TYPE_NORMAL: - case CHAT_TYPE_DIRECT: - break; - case CHAT_TYPE_SHOUT: - chat.mText = LLTrans::getString("shout") + " "; - break; - case CHAT_TYPE_START: - case CHAT_TYPE_STOP: - LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL; - break; - default: - LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; - break; - } - - chat.mText += mesg; - } - - // We have a real utterance now, so can stop showing "..." and proceed. - if (chatter && chatter->isAvatar()) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - ((LLVOAvatar*)chatter)->stopTyping(); - - if (!is_muted && !is_do_not_disturb) - { - //visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); - std::string formated_msg = ""; - LLViewerChat::formatChatMsg(chat, formated_msg); - LLChat chat_bubble = chat; - chat_bubble.mText = formated_msg; - ((LLVOAvatar*)chatter)->addChat(chat_bubble); - } - } - - if (chatter) - { - chat.mPosAgent = chatter->getPositionAgent(); - } - - // truth table: - // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY - // F F F F * Yes Yes - // F F F T * Yes Yes - // F F T F * No No - // F F T T * No No - // F T F F * No Yes - // F T F T * Yes Yes - // F T T F * No No - // F T T T * No No - // T * * * F Yes Yes - - chat.mMuted = is_muted && !is_linden; - - // pass owner_id to chat so that we can display the remote - // object inspect for an object that is chatting with you - LLSD args; - chat.mOwnerID = owner_id; - - LLTranslate::instance().logCharsSeen(mesg.size()); - if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM) - { - if (chat.mChatStyle == CHAT_STYLE_IRC) - { - mesg = mesg.substr(4, std::string::npos); - } - const std::string from_lang = ""; // leave empty to trigger autodetect - const std::string to_lang = LLTranslate::getTranslateLanguage(); - - LLTranslate::instance().logCharsSent(mesg.size()); - LLTranslate::translateMessage(from_lang, to_lang, mesg, - boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2), - boost::bind(&translateFailure, chat, args, _1, _2)); + if (gNonInteractive) + { + return; + } + LLChat chat; + std::string mesg; + std::string from_name; + U8 source_temp; + U8 type_temp; + U8 audible_temp; + LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f); + LLUUID from_id; + LLUUID owner_id; + LLViewerObject* chatter; - } - else - { - LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); - } + msg->getString("ChatData", "FromName", from_name); - // don't call notification for debug messages from not owned objects - if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) - { - if (gAgentID != chat.mOwnerID) - { - return; - } - } + msg->getUUID("ChatData", "SourceID", from_id); + chat.mFromID = from_id; - if (mesg != "") - { - LLSD msg_notify = LLSD(LLSD::emptyMap()); - msg_notify["session_id"] = LLUUID(); - msg_notify["from_id"] = chat.mFromID; - msg_notify["source_type"] = chat.mSourceType; - on_new_message(msg_notify); - } + // Object owner for objects + msg->getUUID("ChatData", "OwnerID", owner_id); - } -} + msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); + chat.mSourceType = (EChatSourceType)source_temp; + msg->getU8("ChatData", "ChatType", type_temp); + chat.mChatType = (EChatType)type_temp; -// Simulator we're on is informing the viewer that the agent -// is starting to teleport (perhaps to another sim, perhaps to the -// same sim). If we initiated the teleport process by sending some kind -// of TeleportRequest, then this info is redundant, but if the sim -// initiated the teleport (via a script call, being killed, etc.) -// then this info is news to us. -void process_teleport_start(LLMessageSystem *msg, void**) -{ - // on teleport, don't tell them about destination guide anymore - LLFirstUse::notUsingDestinationGuide(false); - U32 teleport_flags = 0x0; - msg->getU32("Info", "TeleportFlags", teleport_flags); + msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp); + chat.mAudible = (EChatAudible)audible_temp; - if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) - { - // Race condition? - LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; - } + chat.mTime = LLFrameTimer::getElapsedSeconds(); - LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; + // IDEVO Correct for new-style "Resident" names + if (chat.mSourceType == CHAT_SOURCE_AGENT) + { + // I don't know if it's OK to change this here, if + // anything downstream does lookups by name, for instance - // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM - LLViewerMessage::getInstance()->mTeleportStartedSignal(); + LLAvatarName av_name; + if (LLAvatarNameCache::get(from_id, &av_name)) + { + chat.mFromName = av_name.getCompleteName(); + } + else + { + chat.mFromName = LLCacheName::cleanFullName(from_name); + } + } + else + { + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(from_name); + if (from_name.empty()) + { + from_name = LLTrans::getString("Unnamed"); + } + chat.mFromName = from_name; + } - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) - { - gViewerWindow->setProgressCancelButtonVisible(FALSE); - } - else - { - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); - } + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - // Freeze the UI and show progress bar - // Note: could add data here to differentiate between normal teleport and death. + BOOL is_muted = FALSE; + BOOL is_linden = FALSE; + is_muted = LLMuteList::getInstance()->isMuted( + from_id, + from_name, + LLMute::flagTextChat) + || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat); + is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && + LLMuteList::isLinden(from_name); - if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) - { - gTeleportDisplay = TRUE; - gAgent.setTeleportState( LLAgent::TELEPORT_START ); - make_ui_sound("UISndTeleportOut"); - - LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; + if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) + { + return; + } - // Don't call LLFirstUse::useTeleport here because this could be - // due to being killed, which would send you home, not to a Telehub - } + BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); + chatter = gObjectList.findObject(from_id); + if (chatter) + { + chat.mPosAgent = chatter->getPositionAgent(); + + // Make swirly things only for talking objects. (not script debug messages, though) + if (chat.mSourceType == CHAT_SOURCE_OBJECT + && chat.mChatType != CHAT_TYPE_DEBUG_MSG + && gSavedSettings.getBOOL("EffectScriptChatParticles") ) + { + LLPointer psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); + psc->setSourceObject(chatter); + psc->setColor(color); + //We set the particles to be owned by the object's owner, + //just in case they should be muted by the mute list + psc->setOwnerUUID(owner_id); + LLViewerPartSim::getInstance()->addPartSource(psc); + } + + // record last audible utterance + if (is_audible + && (is_linden || (!is_muted && !is_do_not_disturb))) + { + if (chat.mChatType != CHAT_TYPE_START + && chat.mChatType != CHAT_TYPE_STOP) + { + gAgent.heardChat(chat.mFromID); + } + } + } + + if (is_audible) + { + //BOOL visible_in_chat_bubble = FALSE; + + color.setVec(1.f,1.f,1.f,1.f); + msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); + + BOOL ircstyle = FALSE; + + // Look for IRC-style emotes here so chatbubbles work + std::string prefix = mesg.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + ircstyle = TRUE; + } + chat.mText = mesg; + + // Look for the start of typing so we can put "..." in the bubbles. + if (CHAT_TYPE_START == chat.mChatType) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE); + + // Might not have the avatar constructed yet, eg on login. + if (chatter && chatter->isAvatar()) + { + ((LLVOAvatar*)chatter)->startTyping(); + } + return; + } + else if (CHAT_TYPE_STOP == chat.mChatType) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); + + // Might not have the avatar constructed yet, eg on login. + if (chatter && chatter->isAvatar()) + { + ((LLVOAvatar*)chatter)->stopTyping(); + } + return; + } + + // Look for IRC-style emotes + if (ircstyle) + { + // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656 + chat.mChatStyle = CHAT_STYLE_IRC; + + // Do nothing, ircstyle is fixed above for chat bubbles + } + else + { + chat.mText = ""; + switch(chat.mChatType) + { + case CHAT_TYPE_WHISPER: + chat.mText = LLTrans::getString("whisper") + " "; + break; + case CHAT_TYPE_DEBUG_MSG: + case CHAT_TYPE_OWNER: + case CHAT_TYPE_NORMAL: + case CHAT_TYPE_DIRECT: + break; + case CHAT_TYPE_SHOUT: + chat.mText = LLTrans::getString("shout") + " "; + break; + case CHAT_TYPE_START: + case CHAT_TYPE_STOP: + LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL; + break; + default: + LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; + break; + } + + chat.mText += mesg; + } + + // We have a real utterance now, so can stop showing "..." and proceed. + if (chatter && chatter->isAvatar()) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); + ((LLVOAvatar*)chatter)->stopTyping(); + + if (!is_muted && !is_do_not_disturb) + { + //visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); + std::string formated_msg = ""; + LLViewerChat::formatChatMsg(chat, formated_msg); + LLChat chat_bubble = chat; + chat_bubble.mText = formated_msg; + ((LLVOAvatar*)chatter)->addChat(chat_bubble); + } + } + + if (chatter) + { + chat.mPosAgent = chatter->getPositionAgent(); + } + + // truth table: + // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY + // F F F F * Yes Yes + // F F F T * Yes Yes + // F F T F * No No + // F F T T * No No + // F T F F * No Yes + // F T F T * Yes Yes + // F T T F * No No + // F T T T * No No + // T * * * F Yes Yes + + chat.mMuted = is_muted && !is_linden; + + // pass owner_id to chat so that we can display the remote + // object inspect for an object that is chatting with you + LLSD args; + chat.mOwnerID = owner_id; + + LLTranslate::instance().logCharsSeen(mesg.size()); + if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM) + { + if (chat.mChatStyle == CHAT_STYLE_IRC) + { + mesg = mesg.substr(4, std::string::npos); + } + const std::string from_lang = ""; // leave empty to trigger autodetect + const std::string to_lang = LLTranslate::getTranslateLanguage(); + + LLTranslate::instance().logCharsSent(mesg.size()); + LLTranslate::translateMessage(from_lang, to_lang, mesg, + boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2), + boost::bind(&translateFailure, chat, args, _1, _2)); + + } + else + { + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + } + + // don't call notification for debug messages from not owned objects + if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) + { + if (gAgentID != chat.mOwnerID) + { + return; + } + } + + if (mesg != "") + { + LLSD msg_notify = LLSD(LLSD::emptyMap()); + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + msg_notify["source_type"] = chat.mSourceType; + on_new_message(msg_notify); + } + + } +} + + +// Simulator we're on is informing the viewer that the agent +// is starting to teleport (perhaps to another sim, perhaps to the +// same sim). If we initiated the teleport process by sending some kind +// of TeleportRequest, then this info is redundant, but if the sim +// initiated the teleport (via a script call, being killed, etc.) +// then this info is news to us. +void process_teleport_start(LLMessageSystem *msg, void**) +{ + // on teleport, don't tell them about destination guide anymore + LLFirstUse::notUsingDestinationGuide(false); + U32 teleport_flags = 0x0; + msg->getU32("Info", "TeleportFlags", teleport_flags); + + if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) + { + // Race condition? + LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; + } + + LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; + + // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM + LLViewerMessage::getInstance()->mTeleportStartedSignal(); + + if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) + { + gViewerWindow->setProgressCancelButtonVisible(FALSE); + } + else + { + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); + } + + // Freeze the UI and show progress bar + // Note: could add data here to differentiate between normal teleport and death. + + if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + { + gTeleportDisplay = TRUE; + gAgent.setTeleportState( LLAgent::TELEPORT_START ); + make_ui_sound("UISndTeleportOut"); + + LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; + + // Don't call LLFirstUse::useTeleport here because this could be + // due to being killed, which would send you home, not to a Telehub + } } boost::signals2::connection LLViewerMessage::setTeleportStartedCallback(teleport_started_callback_t cb) { - return mTeleportStartedSignal.connect(cb); + return mTeleportStartedSignal.connect(cb); } void process_teleport_progress(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - if((gAgent.getID() != agent_id) - || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) - { - LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; - return; - } - U32 teleport_flags = 0x0; - msg->getU32("Info", "TeleportFlags", teleport_flags); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) - { - gViewerWindow->setProgressCancelButtonVisible(FALSE); - } - else - { - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); - } - std::string buffer; - msg->getString("Info", "Message", buffer); - LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; - - //Sorta hacky...default to using simulator raw messages - //if we don't find the coresponding mapping in our progress mappings - std::string message = buffer; - - if (LLAgent::sTeleportProgressMessages.find(buffer) != - LLAgent::sTeleportProgressMessages.end() ) - { - message = LLAgent::sTeleportProgressMessages[buffer]; - } - - gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + if((gAgent.getID() != agent_id) + || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) + { + LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; + return; + } + U32 teleport_flags = 0x0; + msg->getU32("Info", "TeleportFlags", teleport_flags); + if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) + { + gViewerWindow->setProgressCancelButtonVisible(FALSE); + } + else + { + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); + } + std::string buffer; + msg->getString("Info", "Message", buffer); + LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; + + //Sorta hacky...default to using simulator raw messages + //if we don't find the coresponding mapping in our progress mappings + std::string message = buffer; + + if (LLAgent::sTeleportProgressMessages.find(buffer) != + LLAgent::sTeleportProgressMessages.end() ) + { + message = LLAgent::sTeleportProgressMessages[buffer]; + } + + gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); } class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea(const uuid_vec_t &ids) : - LLInventoryFetchDescendentsObserver(ids) - {} - virtual void done() - { - LLIsType is_landmark(LLAssetType::AT_LANDMARK); - LLIsType is_card(LLAssetType::AT_CALLINGCARD); - - LLInventoryModel::cat_array_t card_cats; - LLInventoryModel::item_array_t card_items; - LLInventoryModel::cat_array_t land_cats; - LLInventoryModel::item_array_t land_items; - - uuid_vec_t::iterator it = mComplete.begin(); - uuid_vec_t::iterator end = mComplete.end(); - for(; it != end; ++it) - { - gInventory.collectDescendentsIf( - (*it), - land_cats, - land_items, - LLInventoryModel::EXCLUDE_TRASH, - is_landmark); - gInventory.collectDescendentsIf( - (*it), - card_cats, - card_items, - LLInventoryModel::EXCLUDE_TRASH, - is_card); - } - - gInventory.removeObserver(this); - delete this; - } + LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLInventoryFetchDescendentsObserver(ids) + {} + virtual void done() + { + LLIsType is_landmark(LLAssetType::AT_LANDMARK); + LLIsType is_card(LLAssetType::AT_CALLINGCARD); + + LLInventoryModel::cat_array_t card_cats; + LLInventoryModel::item_array_t card_items; + LLInventoryModel::cat_array_t land_cats; + LLInventoryModel::item_array_t land_items; + + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); + for(; it != end; ++it) + { + gInventory.collectDescendentsIf( + (*it), + land_cats, + land_items, + LLInventoryModel::EXCLUDE_TRASH, + is_landmark); + gInventory.collectDescendentsIf( + (*it), + card_cats, + card_items, + LLInventoryModel::EXCLUDE_TRASH, + is_card); + } + + gInventory.removeObserver(this); + delete this; + } }; -class LLPostTeleportNotifiers : public LLEventTimer +class LLPostTeleportNotifiers : public LLEventTimer { public: - LLPostTeleportNotifiers(); - virtual ~LLPostTeleportNotifiers(); + LLPostTeleportNotifiers(); + virtual ~LLPostTeleportNotifiers(); - //function to be called at the supplied frequency - bool tick() override; + //function to be called at the supplied frequency + bool tick() override; }; LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) @@ -2903,34 +2903,34 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() bool LLPostTeleportNotifiers::tick() { - bool all_done = false; - if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) - { - // get callingcards and landmarks available to the user arriving. - uuid_vec_t folders; - const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(callingcard_id.notNull()) - folders.push_back(callingcard_id); - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - if(folder_id.notNull()) - folders.push_back(folder_id); - if(!folders.empty()) - { - LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); - fetcher->startFetch(); - if(fetcher->isFinished()) - { - fetcher->done(); - } - else - { - gInventory.addObserver(fetcher); - } - } - all_done = true; - } - - return all_done; + bool all_done = false; + if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + { + // get callingcards and landmarks available to the user arriving. + uuid_vec_t folders; + const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + if(callingcard_id.notNull()) + folders.push_back(callingcard_id); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + if(folder_id.notNull()) + folders.push_back(folder_id); + if(!folders.empty()) + { + LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); + fetcher->startFetch(); + if(fetcher->isFinished()) + { + fetcher->done(); + } + else + { + gInventory.addObserver(fetcher); + } + } + all_done = true; + } + + return all_done; } @@ -2939,14 +2939,14 @@ bool LLPostTeleportNotifiers::tick() // We're going to pretend to be a new agent void process_teleport_finish(LLMessageSystem* msg, void**) { - LL_DEBUGS("Teleport","Messaging") << "Received TeleportFinish message" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Teleport","Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; - return; - } + LL_DEBUGS("Teleport","Messaging") << "Received TeleportFinish message" << LL_ENDL; + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS("Teleport","Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; + return; + } if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { @@ -2954,7 +2954,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) { // Server either ignored teleport cancel message or did not receive it in time. // This message can't be ignored since teleport is complete at server side - LL_INFOS("Teleport") << "Restoring canceled teleport request" << LL_ENDL; + LL_INFOS("Teleport") << "Restoring canceled teleport request" << LL_ENDL; gAgent.restoreCanceledTeleportRequest(); } else @@ -2971,663 +2971,663 @@ void process_teleport_finish(LLMessageSystem* msg, void**) { LL_WARNS("Teleport","Messaging") << "Teleport message in the middle of other teleport" << LL_ENDL; } - - // Teleport is finished; it can't be cancelled now. - gViewerWindow->setProgressCancelButtonVisible(FALSE); - - // Do teleport effect for where you're leaving - // VEFFECT: TeleportStart - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - - U32 location_id; - U32 sim_ip; - U16 sim_port; - LLVector3 pos, look_at; - U64 region_handle; - msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); - msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip); - msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port); - //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); - //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); - msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle); - U32 teleport_flags; - msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - std::string seedCap; - msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); - - LL_DEBUGS("Teleport") << "TeleportFinish message params are:" - << " sim_ip " << sim_ip - << " sim_port " << sim_port - << " region_handle " << region_handle - << " teleport_flags " << teleport_flags - << " seedCap " << seedCap - << LL_ENDL; - - // update home location if we are teleporting out of prelude - specific to teleporting to welcome area - if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) - && (!gAgent.isGodlike())) - { - gAgent.setHomePosRegion(region_handle, pos); - - // Create a timer that will send notices when teleporting is all finished. Since this is - // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked. - new LLPostTeleportNotifiers(); - } - - LLHost sim_host(sim_ip, sim_port); - - // Viewer trusts the simulator. - gMessageSystem->enableCircuit(sim_host, TRUE); - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + // Teleport is finished; it can't be cancelled now. + gViewerWindow->setProgressCancelButtonVisible(FALSE); + + // Do teleport effect for where you're leaving + // VEFFECT: TeleportStart + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + + U32 location_id; + U32 sim_ip; + U16 sim_port; + LLVector3 pos, look_at; + U64 region_handle; + msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); + msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip); + msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port); + //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); + //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); + msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle); + U32 teleport_flags; + msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + + std::string seedCap; + msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); + + LL_DEBUGS("Teleport") << "TeleportFinish message params are:" + << " sim_ip " << sim_ip + << " sim_port " << sim_port + << " region_handle " << region_handle + << " teleport_flags " << teleport_flags + << " seedCap " << seedCap + << LL_ENDL; + + // update home location if we are teleporting out of prelude - specific to teleporting to welcome area + if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) + && (!gAgent.isGodlike())) + { + gAgent.setHomePosRegion(region_handle, pos); + + // Create a timer that will send notices when teleporting is all finished. Since this is + // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked. + new LLPostTeleportNotifiers(); + } + + LLHost sim_host(sim_ip, sim_port); + + // Viewer trusts the simulator. + gMessageSystem->enableCircuit(sim_host, TRUE); + LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); /* - // send camera update to new region - gAgentCamera.updateCamera(); - - // likewise make sure the camera is behind the avatar - gAgentCamera.resetView(TRUE); - LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal()); - gAgent.setRegion(regionp); - gObjectList.shiftObjects(shift_vector); - - if (isAgentAvatarValid()) - { - gAgentAvatarp->clearChatText(); - gAgentCamera.slamLookAt(look_at); - } - gAgent.setPositionAgent(pos); - gAssetStorage->setUpstream(sim); - gCacheName->setUpstream(sim); + // send camera update to new region + gAgentCamera.updateCamera(); + + // likewise make sure the camera is behind the avatar + gAgentCamera.resetView(TRUE); + LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal()); + gAgent.setRegion(regionp); + gObjectList.shiftObjects(shift_vector); + + if (isAgentAvatarValid()) + { + gAgentAvatarp->clearChatText(); + gAgentCamera.slamLookAt(look_at); + } + gAgent.setPositionAgent(pos); + gAssetStorage->setUpstream(sim); + gCacheName->setUpstream(sim); */ - // Make sure we're standing - gAgent.standUp(); + // Make sure we're standing + gAgent.standUp(); - // now, use the circuit info to tell simulator about us! - LL_INFOS("Teleport","Messaging") << "process_teleport_finish() sending UseCircuitCode to enable sim_host " - << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable(sim_host); + // now, use the circuit info to tell simulator about us! + LL_INFOS("Teleport","Messaging") << "process_teleport_finish() sending UseCircuitCode to enable sim_host " + << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; + msg->newMessageFast(_PREHASH_UseCircuitCode); + msg->nextBlockFast(_PREHASH_CircuitCode); + msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); + msg->sendReliable(sim_host); - LL_INFOS("Teleport") << "Calling send_complete_agent_movement() and setting state to TELEPORT_MOVING" << LL_ENDL; - send_complete_agent_movement(sim_host); - gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); - gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); + LL_INFOS("Teleport") << "Calling send_complete_agent_movement() and setting state to TELEPORT_MOVING" << LL_ENDL; + send_complete_agent_movement(sim_host); + gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); + gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability(). Seed cap == " - << seedCap << LL_ENDL; - regionp->setSeedCapability(seedCap); + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability(). Seed cap == " + << seedCap << LL_ENDL; + regionp->setSeedCapability(seedCap); - // Don't send camera updates to the new region until we're - // actually there... + // Don't send camera updates to the new region until we're + // actually there... - // Now do teleport effect for where you're going. - // VEFFECT: TeleportEnd - effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); + // Now do teleport effect for where you're going. + // VEFFECT: TeleportEnd + effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); -// gTeleportDisplay = TRUE; -// gTeleportDisplayTimer.reset(); -// gViewerWindow->setShowProgress(TRUE); +// gTeleportDisplay = TRUE; +// gTeleportDisplayTimer.reset(); +// gViewerWindow->setShowProgress(TRUE); } // stuff we have to do every time we get an AvatarInitComplete from a sim /* void process_avatar_init_complete(LLMessageSystem* msg, void**) { - LLVector3 agent_pos; - msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos); - agent_movement_complete(msg->getSender(), agent_pos); + LLVector3 agent_pos; + msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos); + agent_movement_complete(msg->getSender(), agent_pos); } */ void process_agent_movement_complete(LLMessageSystem* msg, void**) { - LL_INFOS("Teleport","Messaging") << "Received ProcessAgentMovementComplete" << LL_ENDL; - - gShiftFrame = true; - gAgentMovementCompleted = true; - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) - { - LL_WARNS("Teleport", "Messaging") << "Incorrect agent or session id in process_agent_movement_complete()" - << " agent " << agent_id << " expected " << gAgent.getID() - << " session " << session_id << " expected " << gAgent.getSessionID() - << ", ignoring" << LL_ENDL; - return; - } - - // *TODO: check timestamp to make sure the movement compleation - // makes sense. - LLVector3 agent_pos; - msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos); - LLVector3 look_at; - msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at); - U64 region_handle; - msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle); - - std::string version_channel; - msg->getString("SimData", "ChannelVersion", version_channel); - - if (!isAgentAvatarValid()) - { - // Could happen if you were immediately god-teleported away on login, - // maybe other cases. Continue, but warn. - LL_WARNS("Teleport", "Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; - } - - F32 x, y; - from_region_handle(region_handle, &x, &y); - LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); - if (!regionp) - { - if (gAgent.getRegion()) - { - LL_WARNS("Teleport", "Messaging") << "current region origin " - << gAgent.getRegion()->getOriginGlobal() << " id " << gAgent.getRegion()->getRegionID() << LL_ENDL; - } - - LL_WARNS("Teleport", "Messaging") << "Agent being sent to invalid home region: " - << x << ":" << y - << " current pos " << gAgent.getPositionGlobal() - << ", calling forceDisconnect()" - << LL_ENDL; - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); - return; - - } - - LL_INFOS("Teleport","Messaging") << "Changing home region to region id " << regionp->getRegionID() << " handle " << region_handle << " == x,y " << x << "," << y << LL_ENDL; - - // set our upstream host the new simulator and shuffle things as - // appropriate. - LLVector3 shift_vector = regionp->getPosRegionFromGlobal( - gAgent.getRegion()->getOriginGlobal()); - gAgent.setRegion(regionp); - gObjectList.shiftObjects(shift_vector); - gAssetStorage->setUpstream(msg->getSender()); - gCacheName->setUpstream(msg->getSender()); - gViewerThrottle.sendToSim(); - gViewerWindow->sendShapeToSim(); - - bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - - if( is_teleport ) - { - if (gAgent.getTeleportKeepsLookAt()) - { - // *NOTE: the LookAt data we get from the sim here doesn't - // seem to be useful, so get it from the camera instead - look_at = LLViewerCamera::getInstance()->getAtAxis(); - } - // Force the camera back onto the agent, don't animate. - gAgentCamera.setFocusOnAvatar(TRUE, FALSE); - gAgentCamera.slamLookAt(look_at); - gAgentCamera.updateCamera(); - - LL_INFOS("Teleport") << "Agent movement complete, setting state to TELEPORT_START_ARRIVAL" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); - - if (isAgentAvatarValid()) - { - // Set the new position - gAgentAvatarp->setPositionAgent(agent_pos); - gAgentAvatarp->clearChat(); - gAgentAvatarp->slamPosition(); - } - } - else - { - // This is initial log-in or a region crossing - LL_INFOS("Teleport") << "State is not TELEPORT_MOVING, so this is initial log-in or region crossing. " - << "Setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - - if(LLStartUp::getStartupState() < STATE_STARTED) - { // This is initial log-in, not a region crossing: - // Set the camera looking ahead of the AV so send_agent_update() below - // will report the correct location to the server. - LLVector3 look_at_point = look_at; - look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat()); - - static LLVector3 up_direction(0.0f, 0.0f, 1.0f); - LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction); - } - } - - if ( LLTracker::isTracking(NULL) ) - { - // Check distance to beacon, if < 5m, remove beacon - LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal(); - LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0); - if (beacon_dir.magVecSquared() < 25.f) - { - LLTracker::stopTracking(false); - } - else if ( is_teleport && !gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) - { - //look at the beacon - LLVector3 global_agent_pos = agent_pos; - global_agent_pos[0] += x; - global_agent_pos[1] += y; - look_at = (LLVector3)beacon_pos - global_agent_pos; - look_at.normVec(); - gAgentCamera.slamLookAt(look_at); - } - } - - // TODO: Put back a check for flying status! DK 12/19/05 - // Sim tells us whether the new position is off the ground - /* - if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) - { - gAgent.setFlying(TRUE); - } - else - { - gAgent.setFlying(FALSE); - } - */ - - send_agent_update(TRUE, TRUE); - - if (gAgent.getRegion()->getBlockFly()) - { - gAgent.setFlying(gAgent.canFly()); - } - - // force simulator to recognize do not disturb state - if (gAgent.isDoNotDisturb()) - { - gAgent.setDoNotDisturb(true); - } - else - { - gAgent.setDoNotDisturb(false); - } - - if (isAgentAvatarValid()) - { - gAgentAvatarp->mFootPlane.clearVec(); - } - - // send walk-vs-run status - gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); - - // If the server version has changed, display an info box and offer - // to display the release notes, unless this is the initial log in. - if (gLastVersionChannel == version_channel) - { - return; - } - - gLastVersionChannel = version_channel; -} + LL_INFOS("Teleport","Messaging") << "Received ProcessAgentMovementComplete" << LL_ENDL; -void process_crossed_region(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) - { - LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" - << LL_ENDL; - return; - } - LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; - gAgentAvatarp->resetRegionCrossingTimer(); + gShiftFrame = true; + gAgentMovementCompleted = true; - U32 sim_ip; - msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); - U16 sim_port; - msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port); - LLHost sim_host(sim_ip, sim_port); - U64 region_handle; - msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); - - std::string seedCap; - msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, seedCap); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + { + LL_WARNS("Teleport", "Messaging") << "Incorrect agent or session id in process_agent_movement_complete()" + << " agent " << agent_id << " expected " << gAgent.getID() + << " session " << session_id << " expected " << gAgent.getSessionID() + << ", ignoring" << LL_ENDL; + return; + } - send_complete_agent_movement(sim_host); + // *TODO: check timestamp to make sure the movement compleation + // makes sense. + LLVector3 agent_pos; + msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos); + LLVector3 look_at; + msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at); + U64 region_handle; + msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle); - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + std::string version_channel; + msg->getString("SimData", "ChannelVersion", version_channel); - LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " - << seedCap << LL_ENDL; - regionp->setSeedCapability(seedCap); -} + if (!isAgentAvatarValid()) + { + // Could happen if you were immediately god-teleported away on login, + // maybe other cases. Continue, but warn. + LL_WARNS("Teleport", "Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; + } + F32 x, y; + from_region_handle(region_handle, &x, &y); + LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + if (!regionp) + { + if (gAgent.getRegion()) + { + LL_WARNS("Teleport", "Messaging") << "current region origin " + << gAgent.getRegion()->getOriginGlobal() << " id " << gAgent.getRegion()->getRegionID() << LL_ENDL; + } + LL_WARNS("Teleport", "Messaging") << "Agent being sent to invalid home region: " + << x << ":" << y + << " current pos " << gAgent.getPositionGlobal() + << ", calling forceDisconnect()" + << LL_ENDL; + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); + return; -// Sends avatar and camera information to simulator. -// Sent roughly once per frame, or 20 times per second, whichever is less often + } -const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot -const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot - // between these values we delay the updates (but no more than one second) + LL_INFOS("Teleport","Messaging") << "Changing home region to region id " << regionp->getRegionID() << " handle " << region_handle << " == x,y " << x << "," << y << LL_ENDL; -void send_agent_update(BOOL force_send, BOOL send_reliable) -{ - LL_PROFILE_ZONE_SCOPED; - llassert(!gCubeSnapshot); + // set our upstream host the new simulator and shuffle things as + // appropriate. + LLVector3 shift_vector = regionp->getPosRegionFromGlobal( + gAgent.getRegion()->getOriginGlobal()); + gAgent.setRegion(regionp); + gObjectList.shiftObjects(shift_vector); + gAssetStorage->setUpstream(msg->getSender()); + gCacheName->setUpstream(msg->getSender()); + gViewerThrottle.sendToSim(); + gViewerWindow->sendShapeToSim(); - if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) - { - // We don't care if they want to send an agent update, they're not allowed to until the simulator - // that's the target is ready to receive them (after avatar_init_complete is received) - return; - } - - // We have already requested to log out. Don't send agent updates. - if(LLAppViewer::instance()->logoutRequestSent()) - { - return; - } - - // no region to send update to - if(gAgent.getRegion() == NULL) - { - return; - } - - const F32 TRANSLATE_THRESHOLD = 0.01f; - - // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation - // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change - // Thus, we're actually testing against 0.2 degrees - const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above - - const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent - - // Store data on last sent update so that if no changes, no send - static LLVector3 last_camera_pos_agent, - last_camera_at, - last_camera_left, - last_camera_up; - - static LLVector3 cam_center_chg, - cam_rot_chg; - - static LLQuaternion last_head_rot; - static U32 last_control_flags = 0; - static U8 last_render_state; - static U8 duplicate_count = 0; - static F32 head_rot_chg = 1.0; - static U8 last_flags; - - LLMessageSystem *msg = gMessageSystem; - LLVector3 camera_pos_agent; // local to avatar's region - U8 render_state; - - LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion(); - LLQuaternion head_rotation = gAgent.getHeadRotation(); - - camera_pos_agent = gAgentCamera.getCameraPositionAgent(); - - render_state = gAgent.getRenderState(); - - U32 control_flag_change = 0; - U8 flag_change = 0; - - cam_center_chg = last_camera_pos_agent - camera_pos_agent; - cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis(); - - // If a modifier key is held down, turn off - // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't - // trigger a control event. - U32 control_flags = gAgent.getControlFlags(); - - MASK key_mask = gKeyboard->currentMask(TRUE); - - if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) - { - control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | - AGENT_CONTROL_ML_LBUTTON_DOWN ); - control_flags |= AGENT_CONTROL_LBUTTON_UP | - AGENT_CONTROL_ML_LBUTTON_UP ; - } - - control_flag_change = last_control_flags ^ control_flags; - - U8 flags = AU_FLAGS_NONE; - if (gAgent.isGroupTitleHidden()) - { - flags |= AU_FLAGS_HIDETITLE; - } - if (gAgent.getAutoPilot()) - { - flags |= AU_FLAGS_CLIENT_AUTOPILOT; - } - - flag_change = last_flags ^ flags; - - head_rot_chg = dot(last_head_rot, head_rotation); - - //static S32 msg_number = 0; // Used for diagnostic log messages - - if (force_send || - (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || - (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || - (last_render_state != render_state) || - (cam_rot_chg.magVec() > ROTATION_THRESHOLD) || - control_flag_change != 0 || - flag_change != 0) - { - /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block - msg_number += 1; - if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) - { - //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL; - } - if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) - { - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL; - } - if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) - { - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL; - } -// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) -// { -// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL; -// } - if (control_flag_change) - { - LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL; - } -*/ + bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - duplicate_count = 0; - } - else - { - duplicate_count++; - - if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND) - { - // The head_rotation is sent for updating things like attached guns. - // We only trigger a new update when head_rotation deviates beyond - // some threshold from the last update, however this can break fine - // adjustments when trying to aim an attached gun, so what we do here - // (where we would normally skip sending an update when nothing has changed) - // is gradually reduce the threshold to allow a better update to - // eventually get sent... should update to within 0.5 degrees in less - // than a second. - if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND) - { - duplicate_count = 0; - } - else - { - return; - } - } - else - { - return; - } - } - - if (duplicate_count < DUP_MSGS && !gDisconnected) - { - /* More diagnostics to count AgentUpdate messages - static S32 update_sec = 0; - static S32 update_count = 0; - static S32 max_update_count = 0; - S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() ); - update_count += 1; - if (cur_sec != update_sec) - { - if (update_sec != 0) - { - update_sec = cur_sec; - //msg_number = 0; - max_update_count = llmax(max_update_count, update_count); - LL_INFOS() << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << LL_ENDL; - } - update_sec = cur_sec; - update_count = 0; - } - */ - - // Build the message - msg->newMessageFast(_PREHASH_AgentUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); - msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); - msg->addU8Fast(_PREHASH_State, render_state); - msg->addU8Fast(_PREHASH_Flags, flags); - -// if (camera_pos_agent.mV[VY] > 255.f) -// { -// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; -// } - - msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); - msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); - msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); - msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); - - msg->addU32Fast(_PREHASH_ControlFlags, control_flags); - - if (gDebugClicks) - { - if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) - { - LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; - } - - if (control_flags & AGENT_CONTROL_LBUTTON_UP) - { - LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; - } - } - - gAgent.enableControlFlagReset(); - - if (!send_reliable) - { - gAgent.sendMessage(); - } - else - { - gAgent.sendReliableMessage(); - } - -// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; - - // Copy the old data - last_head_rot = head_rotation; - last_render_state = render_state; - last_camera_pos_agent = camera_pos_agent; - last_camera_at = LLViewerCamera::getInstance()->getAtAxis(); - last_camera_left = LLViewerCamera::getInstance()->getLeftAxis(); - last_camera_up = LLViewerCamera::getInstance()->getUpAxis(); - last_control_flags = control_flags; - last_flags = flags; - } -} + if( is_teleport ) + { + if (gAgent.getTeleportKeepsLookAt()) + { + // *NOTE: the LookAt data we get from the sim here doesn't + // seem to be useful, so get it from the camera instead + look_at = LLViewerCamera::getInstance()->getAtAxis(); + } + // Force the camera back onto the agent, don't animate. + gAgentCamera.setFocusOnAvatar(TRUE, FALSE); + gAgentCamera.slamLookAt(look_at); + gAgentCamera.updateCamera(); + LL_INFOS("Teleport") << "Agent movement complete, setting state to TELEPORT_START_ARRIVAL" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); -// sounds can arrive before objects, store them for a short time -// Note: this is a workaround for MAINT-4743, real fix would be to make -// server send sound along with object update that creates (rezes) the object -class PostponedSoundData -{ -public: - PostponedSoundData() : - mExpirationTime(0) - {} - PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); - bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + if (isAgentAvatarValid()) + { + // Set the new position + gAgentAvatarp->setPositionAgent(agent_pos); + gAgentAvatarp->clearChat(); + gAgentAvatarp->slamPosition(); + } + } + else + { + // This is initial log-in or a region crossing + LL_INFOS("Teleport") << "State is not TELEPORT_MOVING, so this is initial log-in or region crossing. " + << "Setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + + if(LLStartUp::getStartupState() < STATE_STARTED) + { // This is initial log-in, not a region crossing: + // Set the camera looking ahead of the AV so send_agent_update() below + // will report the correct location to the server. + LLVector3 look_at_point = look_at; + look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat()); + + static LLVector3 up_direction(0.0f, 0.0f, 1.0f); + LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction); + } + } - LLUUID mObjectId; - LLUUID mSoundId; - LLUUID mOwnerId; - F32 mGain; - U8 mFlags; - static const F64 MAXIMUM_PLAY_DELAY; + if ( LLTracker::isTracking(NULL) ) + { + // Check distance to beacon, if < 5m, remove beacon + LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal(); + LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0); + if (beacon_dir.magVecSquared() < 25.f) + { + LLTracker::stopTracking(false); + } + else if ( is_teleport && !gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) + { + //look at the beacon + LLVector3 global_agent_pos = agent_pos; + global_agent_pos[0] += x; + global_agent_pos[1] += y; + look_at = (LLVector3)beacon_pos - global_agent_pos; + look_at.normVec(); + gAgentCamera.slamLookAt(look_at); + } + } -private: - F64 mExpirationTime; //seconds since epoch -}; -const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; -static F64 postponed_sounds_update_expiration = 0.0; -static std::map postponed_sounds; + // TODO: Put back a check for flying status! DK 12/19/05 + // Sim tells us whether the new position is off the ground + /* + if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) + { + gAgent.setFlying(TRUE); + } + else + { + gAgent.setFlying(FALSE); + } + */ -void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) -{ - if (LLMuteList::getInstance()->isMuted(object_id)) return; + send_agent_update(TRUE, TRUE); - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + if (gAgent.getRegion()->getBlockFly()) + { + gAgent.setFlying(gAgent.canFly()); + } - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos = objectp->getPositionGlobal(); - if (!gAgent.canAccessMaturityAtGlobal(pos)) + // force simulator to recognize do not disturb state + if (gAgent.isDoNotDisturb()) + { + gAgent.setDoNotDisturb(true); + } + else + { + gAgent.setDoNotDisturb(false); + } + + if (isAgentAvatarValid()) + { + gAgentAvatarp->mFootPlane.clearVec(); + } + + // send walk-vs-run status + gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); + + // If the server version has changed, display an info box and offer + // to display the release notes, unless this is the initial log in. + if (gLastVersionChannel == version_channel) { return; } - objectp->setAttachedSound(sound_id, owner_id, gain, flags); + gLastVersionChannel = version_channel; } -PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) - : - mObjectId(object_id), - mSoundId(sound_id), - mOwnerId(owner_id), - mGain(gain), - mFlags(flags), - mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +void process_crossed_region(LLMessageSystem* msg, void**) { + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + LLUUID session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + { + LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" + << LL_ENDL; + return; + } + LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; + gAgentAvatarp->resetRegionCrossingTimer(); + + U32 sim_ip; + msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); + U16 sim_port; + msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port); + LLHost sim_host(sim_ip, sim_port); + U64 region_handle; + msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + + std::string seedCap; + msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, seedCap); + + send_complete_agent_movement(sim_host); + + LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " + << seedCap << LL_ENDL; + regionp->setSeedCapability(seedCap); } -// static -void update_attached_sounds() + + +// Sends avatar and camera information to simulator. +// Sent roughly once per frame, or 20 times per second, whichever is less often + +const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot +const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot + // between these values we delay the updates (but no more than one second) + +void send_agent_update(BOOL force_send, BOOL send_reliable) { - if (postponed_sounds.empty()) + LL_PROFILE_ZONE_SCOPED; + llassert(!gCubeSnapshot); + + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + // We don't care if they want to send an agent update, they're not allowed to until the simulator + // that's the target is ready to receive them (after avatar_init_complete is received) + return; + } + + // We have already requested to log out. Don't send agent updates. + if(LLAppViewer::instance()->logoutRequestSent()) + { + return; + } + + // no region to send update to + if(gAgent.getRegion() == NULL) + { + return; + } + + const F32 TRANSLATE_THRESHOLD = 0.01f; + + // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation + // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change + // Thus, we're actually testing against 0.2 degrees + const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above + + const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent + + // Store data on last sent update so that if no changes, no send + static LLVector3 last_camera_pos_agent, + last_camera_at, + last_camera_left, + last_camera_up; + + static LLVector3 cam_center_chg, + cam_rot_chg; + + static LLQuaternion last_head_rot; + static U32 last_control_flags = 0; + static U8 last_render_state; + static U8 duplicate_count = 0; + static F32 head_rot_chg = 1.0; + static U8 last_flags; + + LLMessageSystem *msg = gMessageSystem; + LLVector3 camera_pos_agent; // local to avatar's region + U8 render_state; + + LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion(); + LLQuaternion head_rotation = gAgent.getHeadRotation(); + + camera_pos_agent = gAgentCamera.getCameraPositionAgent(); + + render_state = gAgent.getRenderState(); + + U32 control_flag_change = 0; + U8 flag_change = 0; + + cam_center_chg = last_camera_pos_agent - camera_pos_agent; + cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis(); + + // If a modifier key is held down, turn off + // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't + // trigger a control event. + U32 control_flags = gAgent.getControlFlags(); + + MASK key_mask = gKeyboard->currentMask(TRUE); + + if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) + { + control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | + AGENT_CONTROL_ML_LBUTTON_DOWN ); + control_flags |= AGENT_CONTROL_LBUTTON_UP | + AGENT_CONTROL_ML_LBUTTON_UP ; + } + + control_flag_change = last_control_flags ^ control_flags; + + U8 flags = AU_FLAGS_NONE; + if (gAgent.isGroupTitleHidden()) + { + flags |= AU_FLAGS_HIDETITLE; + } + if (gAgent.getAutoPilot()) + { + flags |= AU_FLAGS_CLIENT_AUTOPILOT; + } + + flag_change = last_flags ^ flags; + + head_rot_chg = dot(last_head_rot, head_rotation); + + //static S32 msg_number = 0; // Used for diagnostic log messages + + if (force_send || + (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || + (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || + (last_render_state != render_state) || + (cam_rot_chg.magVec() > ROTATION_THRESHOLD) || + control_flag_change != 0 || + flag_change != 0) + { + /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block + msg_number += 1; + if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) + { + //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL; + } + if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) + { + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL; + } + if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) + { + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL; + } +// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) +// { +// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL; +// } + if (control_flag_change) + { + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL; + } +*/ + + duplicate_count = 0; + } + else + { + duplicate_count++; + + if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND) + { + // The head_rotation is sent for updating things like attached guns. + // We only trigger a new update when head_rotation deviates beyond + // some threshold from the last update, however this can break fine + // adjustments when trying to aim an attached gun, so what we do here + // (where we would normally skip sending an update when nothing has changed) + // is gradually reduce the threshold to allow a better update to + // eventually get sent... should update to within 0.5 degrees in less + // than a second. + if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND) + { + duplicate_count = 0; + } + else + { + return; + } + } + else + { + return; + } + } + + if (duplicate_count < DUP_MSGS && !gDisconnected) + { + /* More diagnostics to count AgentUpdate messages + static S32 update_sec = 0; + static S32 update_count = 0; + static S32 max_update_count = 0; + S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() ); + update_count += 1; + if (cur_sec != update_sec) + { + if (update_sec != 0) + { + update_sec = cur_sec; + //msg_number = 0; + max_update_count = llmax(max_update_count, update_count); + LL_INFOS() << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << LL_ENDL; + } + update_sec = cur_sec; + update_count = 0; + } + */ + + // Build the message + msg->newMessageFast(_PREHASH_AgentUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); + msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); + msg->addU8Fast(_PREHASH_State, render_state); + msg->addU8Fast(_PREHASH_Flags, flags); + +// if (camera_pos_agent.mV[VY] > 255.f) +// { +// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; +// } + + msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); + msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); + msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); + msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); + msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); + + msg->addU32Fast(_PREHASH_ControlFlags, control_flags); + + if (gDebugClicks) + { + if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) + { + LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; + } + + if (control_flags & AGENT_CONTROL_LBUTTON_UP) + { + LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; + } + } + + gAgent.enableControlFlagReset(); + + if (!send_reliable) + { + gAgent.sendMessage(); + } + else + { + gAgent.sendReliableMessage(); + } + +// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; + + // Copy the old data + last_head_rot = head_rotation; + last_render_state = render_state; + last_camera_pos_agent = camera_pos_agent; + last_camera_at = LLViewerCamera::getInstance()->getAtAxis(); + last_camera_left = LLViewerCamera::getInstance()->getLeftAxis(); + last_camera_up = LLViewerCamera::getInstance()->getUpAxis(); + last_control_flags = control_flags; + last_flags = flags; + } +} + + +// sounds can arrive before objects, store them for a short time +// Note: this is a workaround for MAINT-4743, real fix would be to make +// server send sound along with object update that creates (rezes) the object +class PostponedSoundData +{ +public: + PostponedSoundData() : + mExpirationTime(0) + {} + PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); + bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + + LLUUID mObjectId; + LLUUID mSoundId; + LLUUID mOwnerId; + F32 mGain; + U8 mFlags; + static const F64 MAXIMUM_PLAY_DELAY; + +private: + F64 mExpirationTime; //seconds since epoch +}; +const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; +static F64 postponed_sounds_update_expiration = 0.0; +static std::map postponed_sounds; + +void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos = objectp->getPositionGlobal(); + if (!gAgent.canAccessMaturityAtGlobal(pos)) + { + return; + } + + objectp->setAttachedSound(sound_id, owner_id, gain, flags); +} + +PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) + : + mObjectId(object_id), + mSoundId(sound_id), + mOwnerId(owner_id), + mGain(gain), + mFlags(flags), + mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +{ +} + +// static +void update_attached_sounds() +{ + if (postponed_sounds.empty()) { return; } @@ -3681,177 +3681,177 @@ void clear_expired_postponed_sounds() extern U32Bits gObjectData; void process_object_update(LLMessageSystem *mesgsys, void **user_data) -{ - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } - - // Update the object... - S32 old_num_objects = gObjectList.mNumNewObjects; - gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); - if (old_num_objects != gObjectList.mNumNewObjects) - { - update_attached_sounds(); - } +{ + // Update the data counters + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } + + // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; + gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) { - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } - - // Update the object... - S32 old_num_objects = gObjectList.mNumNewObjects; - gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); - if (old_num_objects != gObjectList.mNumNewObjects) - { - update_attached_sounds(); - } + // Update the data counters + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } + + // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; + gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) { - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } + // Update the data counters + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } - // Update the object... - gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED); + // Update the object... + gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED); } void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) { - if (mesgsys->getReceiveCompressedSize()) - { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); - } - else - { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); - } + if (mesgsys->getReceiveCompressedSize()) + { + gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + } + else + { + gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + } - S32 old_num_objects = gObjectList.mNumNewObjects; - gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); - if (old_num_objects != gObjectList.mNumNewObjects) - { - update_attached_sounds(); - } + S32 old_num_objects = gObjectList.mNumNewObjects; + gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } void process_kill_object(LLMessageSystem *mesgsys, void **user_data) { LL_PROFILE_ZONE_SCOPED; - LLUUID id; - - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - LLViewerRegion* regionp = NULL; - { - LLHost host(ip, port); - regionp = LLWorld::getInstance()->getRegion(host); - } - - bool delete_object = LLViewerRegion::sVOCacheCullingEnabled; - S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); - for (S32 i = 0; i < num_objects; ++i) - { - U32 local_id; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - - LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); - if (id == LLUUID::null) - { - LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; - continue; - } - else - { - LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; - } - - if (id == gAgentID) - { - // never kill our avatar - continue; - } - - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) - { - // Display green bubble on kill - if ( gShowObjectUpdates ) - { - LLColor4 color(0.f,1.f,0.f,1.f); - gPipeline.addDebugBlip(objectp->getPositionAgent(), color); - LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; - } - - // Do the kill - gObjectList.killObject(objectp); - } - - if(delete_object) - { - regionp->killCacheEntry(local_id); - } - - // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, + LLUUID id; + + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); + LLViewerRegion* regionp = NULL; + { + LLHost host(ip, port); + regionp = LLWorld::getInstance()->getRegion(host); + } + + bool delete_object = LLViewerRegion::sVOCacheCullingEnabled; + S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (S32 i = 0; i < num_objects; ++i) + { + U32 local_id; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); + + LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); + if (id == LLUUID::null) + { + LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; + continue; + } + else + { + LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; + } + + if (id == gAgentID) + { + // never kill our avatar + continue; + } + + LLViewerObject *objectp = gObjectList.findObject(id); + if (objectp) + { + // Display green bubble on kill + if ( gShowObjectUpdates ) + { + LLColor4 color(0.f,1.f,0.f,1.f); + gPipeline.addDebugBlip(objectp->getPositionAgent(), color); + LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; + } + + // Do the kill + gObjectList.killObject(objectp); + } + + if(delete_object) + { + regionp->killCacheEntry(local_id); + } + + // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, // which is using the object, release the mouse capture correctly when the object dies. // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). - LLSelectMgr::getInstance()->removeObjectFromSelections(id); + LLSelectMgr::getInstance()->removeObjectFromSelections(id); - } // end for loop + } // end for loop LLViewerStatsRecorder::instance().recordObjectKills(num_objects); } void process_time_synch(LLMessageSystem *mesgsys, void **user_data) { - LLVector3 sun_direction; + LLVector3 sun_direction; LLVector3 moon_direction; - LLVector3 sun_ang_velocity; - F32 phase; - U64 space_time_usec; + LLVector3 sun_ang_velocity; + F32 phase; + U64 space_time_usec; U32 seconds_per_day; U32 seconds_per_year; - // "SimulatorViewerTimeMessage" - mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec); - mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day); - mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year); + // "SimulatorViewerTimeMessage" + mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec); + mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day); + mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year); - // This should eventually be moved to an "UpdateHeavenlyBodies" message - mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase); - mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction); - mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity); + // This should eventually be moved to an "UpdateHeavenlyBodies" message + mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase); + mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction); + mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity); - LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); + LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); - LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; + LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; - /* LAPRAS + /* LAPRAS We decode these parts of the message but ignore them as the real values are provided elsewhere. */ (void)sun_direction, (void)moon_direction, (void)phase; @@ -3859,396 +3859,396 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) void process_sound_trigger(LLMessageSystem *msg, void **) { - if (!gAudiop) - { + if (!gAudiop) + { #if !LL_LINUX - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; #endif - return; - } - - U64 region_handle = 0; - F32 gain = 0; - LLUUID sound_id; - LLUUID owner_id; - LLUUID object_id; - LLUUID parent_id; - LLVector3 pos_local; - - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); - msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle); - msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local); - msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain); - - // adjust sound location to true global coords - LLVector3d pos_global = from_region_handle(region_handle); - pos_global.mdV[VX] += pos_local.mV[VX]; - pos_global.mdV[VY] += pos_local.mV[VY]; - pos_global.mdV[VZ] += pos_local.mV[VZ]; - - // Don't play a trigger sound if you can't hear it due - // to parcel "local audio only" settings. - if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return; - - // Don't play sounds triggered by someone you muted. - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - // Don't play sounds from an object you muted - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - // Don't play sounds from an object whose parent you muted - if (parent_id.notNull() - && LLMuteList::getInstance()->isMuted(parent_id)) - { - return; - } - - // Don't play sounds from a region with maturity above current agent maturity - if( !gAgent.canAccessMaturityInRegion( region_handle ) ) - { - return; - } - - // Don't play sounds from gestures if they are not enabled. - // Do play sounds triggered by avatar, since muting your own - // gesture sounds and your own sounds played inworld from - // Inventory can cause confusion. - if (object_id == owner_id + return; + } + + U64 region_handle = 0; + F32 gain = 0; + LLUUID sound_id; + LLUUID owner_id; + LLUUID object_id; + LLUUID parent_id; + LLVector3 pos_local; + + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id); + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); + msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle); + msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local); + msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain); + + // adjust sound location to true global coords + LLVector3d pos_global = from_region_handle(region_handle); + pos_global.mdV[VX] += pos_local.mV[VX]; + pos_global.mdV[VY] += pos_local.mV[VY]; + pos_global.mdV[VZ] += pos_local.mV[VZ]; + + // Don't play a trigger sound if you can't hear it due + // to parcel "local audio only" settings. + if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return; + + // Don't play sounds triggered by someone you muted. + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from an object you muted + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + // Don't play sounds from an object whose parent you muted + if (parent_id.notNull() + && LLMuteList::getInstance()->isMuted(parent_id)) + { + return; + } + + // Don't play sounds from a region with maturity above current agent maturity + if( !gAgent.canAccessMaturityInRegion( region_handle ) ) + { + return; + } + + // Don't play sounds from gestures if they are not enabled. + // Do play sounds triggered by avatar, since muting your own + // gesture sounds and your own sounds played inworld from + // Inventory can cause confusion. + if (object_id == owner_id && owner_id != gAgentID && !gSavedSettings.getBOOL("EnableGestureSounds")) - { - return; - } + { + return; + } - if (LLMaterialTable::basic.isCollisionSound(sound_id) && !gSavedSettings.getBOOL("EnableCollisionSounds")) - { - return; - } + if (LLMaterialTable::basic.isCollisionSound(sound_id) && !gSavedSettings.getBOOL("EnableCollisionSounds")) + { + return; + } - gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global); + gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global); } void process_preload_sound(LLMessageSystem *msg, void **user_data) { - if (!gAudiop) - { + if (!gAudiop) + { #if !LL_LINUX - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; #endif - return; - } + return; + } + + LLUUID sound_id; + LLUUID object_id; + LLUUID owner_id; + + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); - LLUUID sound_id; - LLUUID object_id; - LLUUID owner_id; + LLViewerObject *objectp = gObjectList.findObject(object_id); + if (!objectp) return; - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); + if (LLMuteList::getInstance()->isMuted(object_id)) return; + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) return; + LLAudioSource *sourcep = objectp->getAudioSource(owner_id); + if (!sourcep) return; - if (LLMuteList::getInstance()->isMuted(object_id)) return; - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - LLAudioSource *sourcep = objectp->getAudioSource(owner_id); - if (!sourcep) return; - - LLAudioData *datap = gAudiop->getAudioData(sound_id); + LLAudioData *datap = gAudiop->getAudioData(sound_id); - // Note that I don't actually do any loading of the - // audio data into a buffer at this point, as it won't actually - // help us out. + // Note that I don't actually do any loading of the + // audio data into a buffer at this point, as it won't actually + // help us out. - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos_global = objectp->getPositionGlobal(); - if (gAgent.canAccessMaturityAtGlobal(pos_global)) - { - // Add audioData starts a transfer internally. - sourcep->addAudioData(datap, FALSE); - } + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos_global = objectp->getPositionGlobal(); + if (gAgent.canAccessMaturityAtGlobal(pos_global)) + { + // Add audioData starts a transfer internally. + sourcep->addAudioData(datap, FALSE); + } } void process_attached_sound(LLMessageSystem *msg, void **user_data) { - F32 gain = 0; - LLUUID sound_id; - LLUUID object_id; - LLUUID owner_id; - U8 flags; - - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); - msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); - msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); - - LLViewerObject *objectp = gObjectList.findObject(object_id); - if (objectp) - { - set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); - } - else if (sound_id.notNull()) - { - // we don't know about this object yet, probably it has yet to arrive - // std::map for dupplicate prevention. - postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); - clear_expired_postponed_sounds(); - } - else - { - std::map::iterator iter = postponed_sounds.find(object_id); - if (iter != postponed_sounds.end()) - { - postponed_sounds.erase(iter); - } - } + F32 gain = 0; + LLUUID sound_id; + LLUUID object_id; + LLUUID owner_id; + U8 flags; + + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); + msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); + msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); + msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); + + LLViewerObject *objectp = gObjectList.findObject(object_id); + if (objectp) + { + set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); + } + else if (sound_id.notNull()) + { + // we don't know about this object yet, probably it has yet to arrive + // std::map for dupplicate prevention. + postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); + clear_expired_postponed_sounds(); + } + else + { + std::map::iterator iter = postponed_sounds.find(object_id); + if (iter != postponed_sounds.end()) + { + postponed_sounds.erase(iter); + } + } } void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data) { - F32 gain = 0; - LLUUID object_guid; - LLViewerObject *objectp = NULL; + F32 gain = 0; + LLUUID object_guid; + LLViewerObject *objectp = NULL; - mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); + mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); - if (!((objectp = gObjectList.findObject(object_guid)))) - { - // we don't know about this object, just bail - return; - } + if (!((objectp = gObjectList.findObject(object_guid)))) + { + // we don't know about this object, just bail + return; + } - mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); + mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); - objectp->adjustAudioGain(gain); + objectp->adjustAudioGain(gain); } void process_health_message(LLMessageSystem *mesgsys, void **user_data) { - F32 health; + F32 health; - mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health); + mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health); - if (gStatusBar) - { - gStatusBar->setHealth((S32)health); - } + if (gStatusBar) + { + gStatusBar->setHealth((S32)health); + } } void process_sim_stats(LLMessageSystem *msg, void **user_data) -{ - S32 count = msg->getNumberOfBlocks("Stat"); - for (S32 i = 0; i < count; ++i) - { - U32 stat_id; - F32 stat_value; - msg->getU32("Stat", "StatID", stat_id, i); - msg->getF32("Stat", "StatValue", stat_value, i); - auto measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id); - - if (measurementp ) - { - measurementp->sample(stat_value); - } - else - { - LL_WARNS() << "Unknown sim stat identifier: " << stat_id << LL_ENDL; - } - } - - // - // Various hacks that aren't statistics, but are being handled here. - // - U32 max_tasks_per_region; - U64 region_flags; - msg->getU32("Region", "ObjectCapacity", max_tasks_per_region); - - if (msg->has(_PREHASH_RegionInfo)) - { - msg->getU64("RegionInfo", "RegionFlagsExtended", region_flags); - } - else - { - U32 flags = 0; - msg->getU32("Region", "RegionFlags", flags); - region_flags = flags; - } - - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - BOOL was_flying = gAgent.getFlying(); - regionp->setRegionFlags(region_flags); - regionp->setMaxTasks(max_tasks_per_region); - // HACK: This makes agents drop from the sky if the region is - // set to no fly while people are still in the sim. - if (was_flying && regionp->getBlockFly()) - { - gAgent.setFlying(gAgent.canFly()); - } - } +{ + S32 count = msg->getNumberOfBlocks("Stat"); + for (S32 i = 0; i < count; ++i) + { + U32 stat_id; + F32 stat_value; + msg->getU32("Stat", "StatID", stat_id, i); + msg->getF32("Stat", "StatValue", stat_value, i); + auto measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id); + + if (measurementp ) + { + measurementp->sample(stat_value); + } + else + { + LL_WARNS() << "Unknown sim stat identifier: " << stat_id << LL_ENDL; + } + } + + // + // Various hacks that aren't statistics, but are being handled here. + // + U32 max_tasks_per_region; + U64 region_flags; + msg->getU32("Region", "ObjectCapacity", max_tasks_per_region); + + if (msg->has(_PREHASH_RegionInfo)) + { + msg->getU64("RegionInfo", "RegionFlagsExtended", region_flags); + } + else + { + U32 flags = 0; + msg->getU32("Region", "RegionFlags", flags); + region_flags = flags; + } + + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + BOOL was_flying = gAgent.getFlying(); + regionp->setRegionFlags(region_flags); + regionp->setMaxTasks(max_tasks_per_region); + // HACK: This makes agents drop from the sky if the region is + // set to no fly while people are still in the sim. + if (was_flying && regionp->getBlockFly()) + { + gAgent.setFlying(gAgent.canFly()); + } + } } void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) { - LLUUID animation_id; - LLUUID uuid; - S32 anim_sequence_id; - LLVOAvatar *avatarp = NULL; - - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + LLUUID animation_id; + LLUUID uuid; + S32 anim_sequence_id; + LLVOAvatar *avatarp = NULL; + + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - LLViewerObject *objp = gObjectList.findObject(uuid); + LLViewerObject *objp = gObjectList.findObject(uuid); if (objp) { avatarp = objp->asAvatar(); } - if (!avatarp) - { - // no agent by this ID...error? - LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL; - return; - } - - S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); - S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); - - LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; - - //clear animation flags - avatarp->mSignaledAnimations.clear(); - - if (avatarp->isSelf()) - { - LLUUID object_id; - - for( S32 i = 0; i < num_blocks; i++ ) - { - mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); - mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; - - // *HACK: Disabling flying mode if it has been enabled shortly before the agent - // stand up animation is signaled. In this case we don't get a signal to start - // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the - // avatar does not play flying animation, so we switch flying mode off. - // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink. - // See EXT-2781. - if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying()) - { - gAgent.setFlying(FALSE); - } - - if (i < num_source_blocks) - { - mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i); - - LLViewerObject* object = gObjectList.findObject(object_id); - if (object) - { - object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, TRUE); - - BOOL anim_found = FALSE; - LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); - for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) - { - if (anim_it->first != object_id) - { - // elements with the same key are always contiguous, bail if we went past the - // end of this object's animations - break; - } - if (anim_it->second == animation_id) - { - anim_found = TRUE; - break; - } - } - - if (!anim_found) - { - avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); - } - } - LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id - << " Animation id: " << animation_id - << " From block: " << object_id << LL_ENDL; - } - else - { - LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id - << " Animation id: " << animation_id << LL_ENDL; - } - } - } - else - { - for( S32 i = 0; i < num_blocks; i++ ) - { - mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); - mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; - } - } - - if (num_blocks) - { - avatarp->processAnimationStateChanges(); - } + if (!avatarp) + { + // no agent by this ID...error? + LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL; + return; + } + + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); + S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); + + LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; + + //clear animation flags + avatarp->mSignaledAnimations.clear(); + + if (avatarp->isSelf()) + { + LLUUID object_id; + + for( S32 i = 0; i < num_blocks; i++ ) + { + mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); + mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); + + avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; + + // *HACK: Disabling flying mode if it has been enabled shortly before the agent + // stand up animation is signaled. In this case we don't get a signal to start + // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the + // avatar does not play flying animation, so we switch flying mode off. + // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink. + // See EXT-2781. + if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying()) + { + gAgent.setFlying(FALSE); + } + + if (i < num_source_blocks) + { + mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i); + + LLViewerObject* object = gObjectList.findObject(object_id); + if (object) + { + object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, TRUE); + + BOOL anim_found = FALSE; + LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); + for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) + { + if (anim_it->first != object_id) + { + // elements with the same key are always contiguous, bail if we went past the + // end of this object's animations + break; + } + if (anim_it->second == animation_id) + { + anim_found = TRUE; + break; + } + } + + if (!anim_found) + { + avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); + } + } + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id + << " From block: " << object_id << LL_ENDL; + } + else + { + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id << LL_ENDL; + } + } + } + else + { + for( S32 i = 0; i < num_blocks; i++ ) + { + mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); + mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); + avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; + } + } + + if (num_blocks) + { + avatarp->processAnimationStateChanges(); + } } void process_object_animation(LLMessageSystem *mesgsys, void **user_data) { - LLUUID animation_id; - LLUUID uuid; - S32 anim_sequence_id; - - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + LLUUID animation_id; + LLUUID uuid; + S32 anim_sequence_id; + + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for object " << uuid << LL_ENDL; signaled_animation_map_t signaled_anims; - S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); - LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); + LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; for( S32 i = 0; i < num_blocks; i++ ) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); signaled_anims[animation_id] = anim_sequence_id; - LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object " + LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object " << uuid << " animation id " << animation_id << LL_ENDL; } LLObjectSignaledAnimationMap::instance().getMap()[uuid] = signaled_anims; - + LLViewerObject *objp = gObjectList.findObject(uuid); if (!objp || objp->isDead()) { - LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; return; } - - LLVOVolume *volp = dynamic_cast(objp); + + LLVOVolume *volp = dynamic_cast(objp); if (!volp) { - LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; return; } if (!volp->isAnimatedObject()) { - LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; return; } @@ -4259,7 +4259,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) LL_DEBUGS("AnimatedObjectsNotify") << "Received animation request for object with no control avatar, ignoring " << uuid << LL_ENDL; return; } - + if (!avatarp->mPlaying) { avatarp->mPlaying = true; @@ -4269,315 +4269,315 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mRootVolp->recursiveMarkForUpdate(); } } - + avatarp->updateAnimations(); } void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) { - LLUUID uuid; - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + LLUUID uuid; + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); - if (avatarp) - { - avatarp->processAvatarAppearance( mesgsys ); - } - else - { - LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL; - } + LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); + if (avatarp) + { + avatarp->processAvatarAppearance( mesgsys ); + } + else + { + LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL; + } } void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) { - LLVector4 cameraCollidePlane; - mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); + LLVector4 cameraCollidePlane; + mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); - gAgentCamera.setCameraCollidePlane(cameraCollidePlane); + gAgentCamera.setCameraCollidePlane(cameraCollidePlane); } void near_sit_object(BOOL success, void *data) { - if (success) - { - // Send message to sit on object - gMessageSystem->newMessageFast(_PREHASH_AgentSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } + if (success) + { + // Send message to sit on object + gMessageSystem->newMessageFast(_PREHASH_AgentSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + } } void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) { - LLVector3 sitPosition; - LLQuaternion sitRotation; - LLUUID sitObjectID; - BOOL use_autopilot; - mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID); - mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot); - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition); - mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation); - LLVector3 camera_eye; - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye); - LLVector3 camera_at; - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at); - BOOL force_mouselook; - mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); - - if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > CAMERA_POSITION_THRESHOLD_SQUARED) - { - gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); - } - - gAgentCamera.setForceMouselook(force_mouselook); - // Forcing turning off flying here to prevent flying after pressing "Stand" - // to stand up from an object. See EXT-1655. - gAgent.setFlying(FALSE); - - LLViewerObject* object = gObjectList.findObject(sitObjectID); - if (object) - { - LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); - if (!use_autopilot || (isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot())) - { - //we're already sitting on this object, so don't autopilot - } - else - { - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); - } - } - else - { - LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL; - } + LLVector3 sitPosition; + LLQuaternion sitRotation; + LLUUID sitObjectID; + BOOL use_autopilot; + mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID); + mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot); + mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition); + mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation); + LLVector3 camera_eye; + mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye); + LLVector3 camera_at; + mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at); + BOOL force_mouselook; + mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); + + if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > CAMERA_POSITION_THRESHOLD_SQUARED) + { + gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); + } + + gAgentCamera.setForceMouselook(force_mouselook); + // Forcing turning off flying here to prevent flying after pressing "Stand" + // to stand up from an object. See EXT-1655. + gAgent.setFlying(FALSE); + + LLViewerObject* object = gObjectList.findObject(sitObjectID); + if (object) + { + LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); + if (!use_autopilot || (isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot())) + { + //we're already sitting on this object, so don't autopilot + } + else + { + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); + } + } + else + { + LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL; + } } void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) { - LLUUID source_id; + LLUUID source_id; - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - LLFollowCamMgr::getInstance()->removeFollowCamParams(source_id); + LLFollowCamMgr::getInstance()->removeFollowCamParams(source_id); } void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) { - S32 type; - F32 value; - bool settingPosition = false; - bool settingFocus = false; - bool settingFocusOffset = false; - LLVector3 position; - LLVector3 focus; - LLVector3 focus_offset; - - LLUUID source_id; - - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - - LLViewerObject* objectp = gObjectList.findObject(source_id); - if (objectp) - { - objectp->setFlagsWithoutUpdate(FLAGS_CAMERA_SOURCE, TRUE); - } - - S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); - for (S32 block_index = 0; block_index < num_objects; block_index++) - { - mesgsys->getS32("CameraProperty", "Type", type, block_index); - mesgsys->getF32("CameraProperty", "Value", value, block_index); - switch(type) - { - case FOLLOWCAM_PITCH: - LLFollowCamMgr::getInstance()->setPitch(source_id, value); - break; - case FOLLOWCAM_FOCUS_OFFSET_X: - focus_offset.mV[VX] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_FOCUS_OFFSET_Y: - focus_offset.mV[VY] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_FOCUS_OFFSET_Z: - focus_offset.mV[VZ] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_POSITION_LAG: - LLFollowCamMgr::getInstance()->setPositionLag(source_id, value); - break; - case FOLLOWCAM_FOCUS_LAG: - LLFollowCamMgr::getInstance()->setFocusLag(source_id, value); - break; - case FOLLOWCAM_DISTANCE: - LLFollowCamMgr::getInstance()->setDistance(source_id, value); - break; - case FOLLOWCAM_BEHINDNESS_ANGLE: - LLFollowCamMgr::getInstance()->setBehindnessAngle(source_id, value); - break; - case FOLLOWCAM_BEHINDNESS_LAG: - LLFollowCamMgr::getInstance()->setBehindnessLag(source_id, value); - break; - case FOLLOWCAM_POSITION_THRESHOLD: - LLFollowCamMgr::getInstance()->setPositionThreshold(source_id, value); - break; - case FOLLOWCAM_FOCUS_THRESHOLD: - LLFollowCamMgr::getInstance()->setFocusThreshold(source_id, value); - break; - case FOLLOWCAM_ACTIVE: - //if 1, set using followcam,. - LLFollowCamMgr::getInstance()->setCameraActive(source_id, value != 0.f); - break; - case FOLLOWCAM_POSITION_X: - settingPosition = true; - position.mV[ 0 ] = value; - break; - case FOLLOWCAM_POSITION_Y: - settingPosition = true; - position.mV[ 1 ] = value; - break; - case FOLLOWCAM_POSITION_Z: - settingPosition = true; - position.mV[ 2 ] = value; - break; - case FOLLOWCAM_FOCUS_X: - settingFocus = true; - focus.mV[ 0 ] = value; - break; - case FOLLOWCAM_FOCUS_Y: - settingFocus = true; - focus.mV[ 1 ] = value; - break; - case FOLLOWCAM_FOCUS_Z: - settingFocus = true; - focus.mV[ 2 ] = value; - break; - case FOLLOWCAM_POSITION_LOCKED: - LLFollowCamMgr::getInstance()->setPositionLocked(source_id, value != 0.f); - break; - case FOLLOWCAM_FOCUS_LOCKED: - LLFollowCamMgr::getInstance()->setFocusLocked(source_id, value != 0.f); - break; - - default: - break; - } - } - - if ( settingPosition ) - { - LLFollowCamMgr::getInstance()->setPosition(source_id, position); - } - if ( settingFocus ) - { - LLFollowCamMgr::getInstance()->setFocus(source_id, focus); - } - if ( settingFocusOffset ) - { - LLFollowCamMgr::getInstance()->setFocusOffset(source_id, focus_offset); - } -} -//end Ventrella + S32 type; + F32 value; + bool settingPosition = false; + bool settingFocus = false; + bool settingFocusOffset = false; + LLVector3 position; + LLVector3 focus; + LLVector3 focus_offset; + + LLUUID source_id; + + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); + + LLViewerObject* objectp = gObjectList.findObject(source_id); + if (objectp) + { + objectp->setFlagsWithoutUpdate(FLAGS_CAMERA_SOURCE, TRUE); + } + + S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); + for (S32 block_index = 0; block_index < num_objects; block_index++) + { + mesgsys->getS32("CameraProperty", "Type", type, block_index); + mesgsys->getF32("CameraProperty", "Value", value, block_index); + switch(type) + { + case FOLLOWCAM_PITCH: + LLFollowCamMgr::getInstance()->setPitch(source_id, value); + break; + case FOLLOWCAM_FOCUS_OFFSET_X: + focus_offset.mV[VX] = value; + settingFocusOffset = true; + break; + case FOLLOWCAM_FOCUS_OFFSET_Y: + focus_offset.mV[VY] = value; + settingFocusOffset = true; + break; + case FOLLOWCAM_FOCUS_OFFSET_Z: + focus_offset.mV[VZ] = value; + settingFocusOffset = true; + break; + case FOLLOWCAM_POSITION_LAG: + LLFollowCamMgr::getInstance()->setPositionLag(source_id, value); + break; + case FOLLOWCAM_FOCUS_LAG: + LLFollowCamMgr::getInstance()->setFocusLag(source_id, value); + break; + case FOLLOWCAM_DISTANCE: + LLFollowCamMgr::getInstance()->setDistance(source_id, value); + break; + case FOLLOWCAM_BEHINDNESS_ANGLE: + LLFollowCamMgr::getInstance()->setBehindnessAngle(source_id, value); + break; + case FOLLOWCAM_BEHINDNESS_LAG: + LLFollowCamMgr::getInstance()->setBehindnessLag(source_id, value); + break; + case FOLLOWCAM_POSITION_THRESHOLD: + LLFollowCamMgr::getInstance()->setPositionThreshold(source_id, value); + break; + case FOLLOWCAM_FOCUS_THRESHOLD: + LLFollowCamMgr::getInstance()->setFocusThreshold(source_id, value); + break; + case FOLLOWCAM_ACTIVE: + //if 1, set using followcam,. + LLFollowCamMgr::getInstance()->setCameraActive(source_id, value != 0.f); + break; + case FOLLOWCAM_POSITION_X: + settingPosition = true; + position.mV[ 0 ] = value; + break; + case FOLLOWCAM_POSITION_Y: + settingPosition = true; + position.mV[ 1 ] = value; + break; + case FOLLOWCAM_POSITION_Z: + settingPosition = true; + position.mV[ 2 ] = value; + break; + case FOLLOWCAM_FOCUS_X: + settingFocus = true; + focus.mV[ 0 ] = value; + break; + case FOLLOWCAM_FOCUS_Y: + settingFocus = true; + focus.mV[ 1 ] = value; + break; + case FOLLOWCAM_FOCUS_Z: + settingFocus = true; + focus.mV[ 2 ] = value; + break; + case FOLLOWCAM_POSITION_LOCKED: + LLFollowCamMgr::getInstance()->setPositionLocked(source_id, value != 0.f); + break; + case FOLLOWCAM_FOCUS_LOCKED: + LLFollowCamMgr::getInstance()->setFocusLocked(source_id, value != 0.f); + break; + + default: + break; + } + } + + if ( settingPosition ) + { + LLFollowCamMgr::getInstance()->setPosition(source_id, position); + } + if ( settingFocus ) + { + LLFollowCamMgr::getInstance()->setFocus(source_id, focus); + } + if ( settingFocusOffset ) + { + LLFollowCamMgr::getInstance()->setFocusOffset(source_id, focus_offset); + } +} +//end Ventrella // Culled from newsim lltask.cpp void process_name_value(LLMessageSystem *mesgsys, void **user_data) { - std::string temp_str; - LLUUID id; - S32 i, num_blocks; + std::string temp_str; + LLUUID id; + S32 i, num_blocks; - mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); + mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); - LLViewerObject* object = gObjectList.findObject(id); + LLViewerObject* object = gObjectList.findObject(id); - if (object) - { - num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); - for (i = 0; i < num_blocks; i++) - { - mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); - LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL; - object->addNVPair(temp_str); - } - } - else - { - LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL; - } + if (object) + { + num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); + for (i = 0; i < num_blocks; i++) + { + mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); + LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL; + object->addNVPair(temp_str); + } + } + else + { + LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL; + } } void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) { - std::string temp_str; - LLUUID id; - S32 i, num_blocks; + std::string temp_str; + LLUUID id; + S32 i, num_blocks; - mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); + mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); - LLViewerObject* object = gObjectList.findObject(id); + LLViewerObject* object = gObjectList.findObject(id); - if (object) - { - num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); - for (i = 0; i < num_blocks; i++) - { - mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); - LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL; - object->removeNVPair(temp_str); - } - } - else - { - LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL; - } + if (object) + { + num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); + for (i = 0; i < num_blocks; i++) + { + mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); + LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL; + object->removeNVPair(temp_str); + } + } + else + { + LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL; + } } void process_kick_user(LLMessageSystem *msg, void** /*user_data*/) { - std::string message; + std::string message; - msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, message); + msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, message); - LLAppViewer::instance()->forceDisconnect(message); + LLAppViewer::instance()->forceDisconnect(message); } /* void process_user_list_reply(LLMessageSystem *msg, void **user_data) { - LLUserList::processUserListReply(msg, user_data); - return; - char firstname[MAX_STRING+1]; - char lastname[MAX_STRING+1]; - U8 status; - S32 user_count; - - user_count = msg->getNumberOfBlocks("UserBlock"); - - for (S32 i = 0; i < user_count; i++) - { - msg->getData("UserBlock", i, "FirstName", firstname); - msg->getData("UserBlock", i, "LastName", lastname); - msg->getData("UserBlock", i, "Status", &status); - - if (status & 0x01) - { - dialog_friends_add_friend(buffer, TRUE); - } - else - { - dialog_friends_add_friend(buffer, FALSE); - } - } - - dialog_friends_done_adding(); + LLUserList::processUserListReply(msg, user_data); + return; + char firstname[MAX_STRING+1]; + char lastname[MAX_STRING+1]; + U8 status; + S32 user_count; + + user_count = msg->getNumberOfBlocks("UserBlock"); + + for (S32 i = 0; i < user_count; i++) + { + msg->getData("UserBlock", i, "FirstName", firstname); + msg->getData("UserBlock", i, "LastName", lastname); + msg->getData("UserBlock", i, "Status", &status); + + if (status & 0x01) + { + dialog_friends_add_friend(buffer, TRUE); + } + else + { + dialog_friends_add_friend(buffer, FALSE); + } + } + + dialog_friends_done_adding(); } */ @@ -4585,635 +4585,635 @@ void process_user_list_reply(LLMessageSystem *msg, void **user_data) /* void process_time_dilation(LLMessageSystem *msg, void **user_data) { - // get the time_dilation - U16 foo; - msg->getData("TimeDilation", "TimeDilation", &foo); - F32 time_dilation = ((F32) foo) / 65535.f; + // get the time_dilation + U16 foo; + msg->getData("TimeDilation", "TimeDilation", &foo); + F32 time_dilation = ((F32) foo) / 65535.f; - // get the pointer to the right region - U32 ip = msg->getSenderIP(); - U32 port = msg->getSenderPort(); - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port); - if (regionp) - { - regionp->setTimeDilation(time_dilation); - } + // get the pointer to the right region + U32 ip = msg->getSenderIP(); + U32 port = msg->getSenderPort(); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port); + if (regionp) + { + regionp->setTimeDilation(time_dilation); + } } */ void process_money_balance_reply( LLMessageSystem* msg, void** ) { - S32 balance = 0; - S32 credit = 0; - S32 committed = 0; - std::string desc; - LLUUID tid; - - msg->getUUID("MoneyData", "TransactionID", tid); - msg->getS32("MoneyData", "MoneyBalance", balance); - msg->getS32("MoneyData", "SquareMetersCredit", credit); - msg->getS32("MoneyData", "SquareMetersCommitted", committed); - msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc); - LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " " - << committed << LL_ENDL; - - if (gStatusBar) - { - gStatusBar->setBalance(balance); - gStatusBar->setLandCredit(credit); - gStatusBar->setLandCommitted(committed); - } - - if (desc.empty() - || !gSavedSettings.getBOOL("NotifyMoneyChange")) - { - // ...nothing to display - return; - } - - // Suppress duplicate messages about the same transaction - static std::deque recent; - if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend()) - { - return; - } - - // Once the 'recent' container gets large enough, chop some - // off the beginning. - const U32 MAX_LOOKBACK = 30; - const S32 POP_FRONT_SIZE = 12; - if(recent.size() > MAX_LOOKBACK) - { - LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; - recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); - } - //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; - recent.push_back(tid); - - if (msg->has("TransactionInfo")) - { - // ...message has extended info for localization - process_money_balance_reply_extended(msg); - } - else - { - // Only old dev grids will not supply the TransactionInfo block, - // so we can just use the hard-coded English string. - LLSD args; - args["MESSAGE"] = desc; - LLNotificationsUtil::add("SystemMessage", args); - } + S32 balance = 0; + S32 credit = 0; + S32 committed = 0; + std::string desc; + LLUUID tid; + + msg->getUUID("MoneyData", "TransactionID", tid); + msg->getS32("MoneyData", "MoneyBalance", balance); + msg->getS32("MoneyData", "SquareMetersCredit", credit); + msg->getS32("MoneyData", "SquareMetersCommitted", committed); + msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc); + LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " " + << committed << LL_ENDL; + + if (gStatusBar) + { + gStatusBar->setBalance(balance); + gStatusBar->setLandCredit(credit); + gStatusBar->setLandCommitted(committed); + } + + if (desc.empty() + || !gSavedSettings.getBOOL("NotifyMoneyChange")) + { + // ...nothing to display + return; + } + + // Suppress duplicate messages about the same transaction + static std::deque recent; + if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend()) + { + return; + } + + // Once the 'recent' container gets large enough, chop some + // off the beginning. + const U32 MAX_LOOKBACK = 30; + const S32 POP_FRONT_SIZE = 12; + if(recent.size() > MAX_LOOKBACK) + { + LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; + recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); + } + //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; + recent.push_back(tid); + + if (msg->has("TransactionInfo")) + { + // ...message has extended info for localization + process_money_balance_reply_extended(msg); + } + else + { + // Only old dev grids will not supply the TransactionInfo block, + // so we can just use the hard-coded English string. + LLSD args; + args["MESSAGE"] = desc; + LLNotificationsUtil::add("SystemMessage", args); + } } static std::string reason_from_transaction_type(S32 transaction_type, - const std::string& item_desc) -{ - // *NOTE: The keys for the reason strings are unusual because - // an earlier version of the code used English language strings - // extracted from hard-coded server English descriptions. - // Keeping them so we don't have to re-localize them. - switch (transaction_type) - { - case TRANS_OBJECT_SALE: - { - LLStringUtil::format_map_t arg; - arg["ITEM"] = item_desc; - return LLTrans::getString("for item", arg); - } - case TRANS_LAND_SALE: - return LLTrans::getString("for a parcel of land"); - - case TRANS_LAND_PASS_SALE: - return LLTrans::getString("for a land access pass"); - - case TRANS_GROUP_LAND_DEED: - return LLTrans::getString("for deeding land"); - - case TRANS_GROUP_CREATE: - return LLTrans::getString("to create a group"); - - case TRANS_GROUP_JOIN: - return LLTrans::getString("to join a group"); - - case TRANS_UPLOAD_CHARGE: - return LLTrans::getString("to upload"); - - case TRANS_CLASSIFIED_CHARGE: - return LLTrans::getString("to publish a classified ad"); - - case TRANS_GIFT: - // Simulator returns "Payment" if no custom description has been entered - return (item_desc == "Payment" ? std::string() : item_desc); - - // These have no reason to display, but are expected and should not - // generate warnings - case TRANS_PAY_OBJECT: - case TRANS_OBJECT_PAYS: - return std::string(); - - default: - LL_WARNS() << "Unknown transaction type " - << transaction_type << LL_ENDL; - return std::string(); - } + const std::string& item_desc) +{ + // *NOTE: The keys for the reason strings are unusual because + // an earlier version of the code used English language strings + // extracted from hard-coded server English descriptions. + // Keeping them so we don't have to re-localize them. + switch (transaction_type) + { + case TRANS_OBJECT_SALE: + { + LLStringUtil::format_map_t arg; + arg["ITEM"] = item_desc; + return LLTrans::getString("for item", arg); + } + case TRANS_LAND_SALE: + return LLTrans::getString("for a parcel of land"); + + case TRANS_LAND_PASS_SALE: + return LLTrans::getString("for a land access pass"); + + case TRANS_GROUP_LAND_DEED: + return LLTrans::getString("for deeding land"); + + case TRANS_GROUP_CREATE: + return LLTrans::getString("to create a group"); + + case TRANS_GROUP_JOIN: + return LLTrans::getString("to join a group"); + + case TRANS_UPLOAD_CHARGE: + return LLTrans::getString("to upload"); + + case TRANS_CLASSIFIED_CHARGE: + return LLTrans::getString("to publish a classified ad"); + + case TRANS_GIFT: + // Simulator returns "Payment" if no custom description has been entered + return (item_desc == "Payment" ? std::string() : item_desc); + + // These have no reason to display, but are expected and should not + // generate warnings + case TRANS_PAY_OBJECT: + case TRANS_OBJECT_PAYS: + return std::string(); + + default: + LL_WARNS() << "Unknown transaction type " + << transaction_type << LL_ENDL; + return std::string(); + } } static void money_balance_group_notify(const LLUUID& group_id, - const std::string& name, - bool is_group, - std::string notification, - LLSD args, - LLSD payload) + const std::string& name, + bool is_group, + std::string notification, + LLSD args, + LLSD payload) { - // Message uses name SLURLs, don't actually have to substitute in - // the name. We're just making sure it's available. - // Notification is either PaymentReceived or PaymentSent - LLNotificationsUtil::add(notification, args, payload); + // Message uses name SLURLs, don't actually have to substitute in + // the name. We're just making sure it's available. + // Notification is either PaymentReceived or PaymentSent + LLNotificationsUtil::add(notification, args, payload); } static void money_balance_avatar_notify(const LLUUID& agent_id, - const LLAvatarName& av_name, - std::string notification, - LLSD args, - LLSD payload) + const LLAvatarName& av_name, + std::string notification, + LLSD args, + LLSD payload) { - // Message uses name SLURLs, don't actually have to substitute in - // the name. We're just making sure it's available. - // Notification is either PaymentReceived or PaymentSent - LLNotificationsUtil::add(notification, args, payload); + // Message uses name SLURLs, don't actually have to substitute in + // the name. We're just making sure it's available. + // Notification is either PaymentReceived or PaymentSent + LLNotificationsUtil::add(notification, args, payload); } -static void process_money_balance_reply_extended(LLMessageSystem* msg) -{ - // Added in server 1.40 and viewer 2.1, support for localization - // and agent ids for name lookup. - S32 transaction_type = 0; - LLUUID source_id; - BOOL is_source_group = FALSE; - LLUUID dest_id; - BOOL is_dest_group = FALSE; - S32 amount = 0; - std::string item_description; - BOOL success = FALSE; +static void process_money_balance_reply_extended(LLMessageSystem* msg) +{ + // Added in server 1.40 and viewer 2.1, support for localization + // and agent ids for name lookup. + S32 transaction_type = 0; + LLUUID source_id; + BOOL is_source_group = FALSE; + LLUUID dest_id; + BOOL is_dest_group = FALSE; + S32 amount = 0; + std::string item_description; + BOOL success = FALSE; + + msg->getS32("TransactionInfo", "TransactionType", transaction_type); + msg->getUUID("TransactionInfo", "SourceID", source_id); + msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group); + msg->getUUID("TransactionInfo", "DestID", dest_id); + msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); + msg->getS32("TransactionInfo", "Amount", amount); + msg->getString("TransactionInfo", "ItemDescription", item_description); + msg->getBOOL("MoneyData", "TransactionSuccess", success); + LL_INFOS("Money") << "MoneyBalanceReply source " << source_id + << " dest " << dest_id + << " type " << transaction_type + << " item " << item_description << LL_ENDL; + + if (source_id.isNull() && dest_id.isNull()) + { + // this is a pure balance update, no notification required + return; + } + + std::string source_slurl; + if (is_source_group) + { + source_slurl = + LLSLURL( "group", source_id, "inspect").getSLURLString(); + } + else + { + source_slurl = + LLSLURL( "agent", source_id, "completename").getSLURLString(); + } + + std::string dest_slurl; + if (is_dest_group) + { + dest_slurl = + LLSLURL( "group", dest_id, "inspect").getSLURLString(); + } + else + { + dest_slurl = + LLSLURL( "agent", dest_id, "completename").getSLURLString(); + } + + std::string reason = + reason_from_transaction_type(transaction_type, item_description); + + LLStringUtil::format_map_t args; + args["REASON"] = reason; // could be empty + args["AMOUNT"] = llformat("%d", amount); + + // Need to delay until name looked up, so need to know whether or not + // is group + bool is_name_group = false; + LLUUID name_id; + std::string message; + std::string notification; + LLSD final_args; + LLSD payload; + + bool you_paid_someone = (source_id == gAgentID); + std::string gift_suffix = (transaction_type == TRANS_GIFT ? "_gift" : ""); + if (you_paid_someone) + { + if(!gSavedSettings.getBOOL("NotifyMoneySpend")) + { + return; + } + args["NAME"] = dest_slurl; + is_name_group = is_dest_group; + name_id = dest_id; + if (!reason.empty()) + { + if (dest_id.notNull()) + { + message = success ? LLTrans::getString("you_paid_ldollars" + gift_suffix, args) : + LLTrans::getString("you_paid_failure_ldollars" + gift_suffix, args); + } + else + { + // transaction fee to the system, eg, to create a group + message = success ? LLTrans::getString("you_paid_ldollars_no_name", args) : + LLTrans::getString("you_paid_failure_ldollars_no_name", args); + } + } + else + { + if (dest_id.notNull()) + { + message = success ? LLTrans::getString("you_paid_ldollars_no_reason", args) : + LLTrans::getString("you_paid_failure_ldollars_no_reason", args); + } + else + { + // no target, no reason, you just paid money + message = success ? LLTrans::getString("you_paid_ldollars_no_info", args) : + LLTrans::getString("you_paid_failure_ldollars_no_info", args); + } + } + final_args["MESSAGE"] = message; + payload["dest_id"] = dest_id; + notification = success ? "PaymentSent" : "PaymentFailure"; + } + else + { + // ...someone paid you + if(!gSavedSettings.getBOOL("NotifyMoneyReceived")) + { + return; + } + args["NAME"] = source_slurl; + is_name_group = is_source_group; + name_id = source_id; + + if (!reason.empty() && !LLMuteList::getInstance()->isMuted(source_id)) + { + message = LLTrans::getString("paid_you_ldollars" + gift_suffix, args); + } + else + { + message = LLTrans::getString("paid_you_ldollars_no_reason", args); + } + final_args["MESSAGE"] = message; + + // make notification loggable + payload["from_id"] = source_id; + notification = "PaymentReceived"; + } + + // Despite using SLURLs, wait until the name is available before + // showing the notification, otherwise the UI layout is strange and + // the user sees a "Loading..." message + if (is_name_group) + { + gCacheName->getGroup(name_id, + boost::bind(&money_balance_group_notify, + _1, _2, _3, + notification, final_args, payload)); + } + else + { + LLAvatarNameCache::get(name_id, boost::bind(&money_balance_avatar_notify, _1, _2, notification, final_args, payload)); + } +} + +bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + // set the preference to the maturity of the region we're calling + U8 preferredMaturity = static_cast(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast(preferredMaturity)); + } + + return false; +} + +bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + // set the preference to the maturity of the region we're calling + U8 preferredMaturity = static_cast(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast(preferredMaturity)); + gAgent.setMaturityRatingChangeDuringTeleport(preferredMaturity); + gAgent.restartFailedTeleportRequest(); + } + else + { + gAgent.clearTeleportRequest(); + } + + return false; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) +{ + bool returnValue = false; + if(llsdBlock.has("_region_access")) + { + U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + + if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + } + + return returnValue; +} + +bool handle_trusted_experiences_notification(const LLSD& llsdBlock) +{ + if(llsdBlock.has("trusted_experiences")) + { + std::ostringstream str; + const LLSD& experiences = llsdBlock["trusted_experiences"]; + LLSD::array_const_iterator it = experiences.beginArray(); + for(/**/; it != experiences.endArray(); ++it) + { + str<asUUID(), "profile").getSLURLString() << "\n"; + } + std::string str_list = str.str(); + if(!str_list.empty()) + { + LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list)); + return true; + } + } + return false; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage) +{ + bool returnValue = false; + if(llsdBlock.has("_region_access")) + { + U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + + LLNotificationPtr tp_failure_notification; + std::string notifySuffix; + + if (notificationID == std::string("TeleportEntryAccessBlocked")) + { + notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + } // End of special handling for "TeleportEntryAccessBlocked" + else + { // Normal case, no message munging + gAgent.clearTeleportRequest(); + if (LLNotifications::getInstance()->templateExists(notificationID)) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); + } + else + { + llsdBlock["MESSAGE"] = defaultMessage; + tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); + } + returnValue = true; + } + + if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored()) + { + // Given a simple notification if no tp_failure_notification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + } - msg->getS32("TransactionInfo", "TransactionType", transaction_type); - msg->getUUID("TransactionInfo", "SourceID", source_id); - msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group); - msg->getUUID("TransactionInfo", "DestID", dest_id); - msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); - msg->getS32("TransactionInfo", "Amount", amount); - msg->getString("TransactionInfo", "ItemDescription", item_description); - msg->getBOOL("MoneyData", "TransactionSuccess", success); - LL_INFOS("Money") << "MoneyBalanceReply source " << source_id - << " dest " << dest_id - << " type " << transaction_type - << " item " << item_description << LL_ENDL; - - if (source_id.isNull() && dest_id.isNull()) - { - // this is a pure balance update, no notification required - return; - } - - std::string source_slurl; - if (is_source_group) - { - source_slurl = - LLSLURL( "group", source_id, "inspect").getSLURLString(); - } - else - { - source_slurl = - LLSLURL( "agent", source_id, "completename").getSLURLString(); - } - - std::string dest_slurl; - if (is_dest_group) - { - dest_slurl = - LLSLURL( "group", dest_id, "inspect").getSLURLString(); - } - else - { - dest_slurl = - LLSLURL( "agent", dest_id, "completename").getSLURLString(); - } - - std::string reason = - reason_from_transaction_type(transaction_type, item_description); - - LLStringUtil::format_map_t args; - args["REASON"] = reason; // could be empty - args["AMOUNT"] = llformat("%d", amount); - - // Need to delay until name looked up, so need to know whether or not - // is group - bool is_name_group = false; - LLUUID name_id; - std::string message; - std::string notification; - LLSD final_args; - LLSD payload; - - bool you_paid_someone = (source_id == gAgentID); - std::string gift_suffix = (transaction_type == TRANS_GIFT ? "_gift" : ""); - if (you_paid_someone) - { - if(!gSavedSettings.getBOOL("NotifyMoneySpend")) - { - return; - } - args["NAME"] = dest_slurl; - is_name_group = is_dest_group; - name_id = dest_id; - if (!reason.empty()) - { - if (dest_id.notNull()) - { - message = success ? LLTrans::getString("you_paid_ldollars" + gift_suffix, args) : - LLTrans::getString("you_paid_failure_ldollars" + gift_suffix, args); - } - else - { - // transaction fee to the system, eg, to create a group - message = success ? LLTrans::getString("you_paid_ldollars_no_name", args) : - LLTrans::getString("you_paid_failure_ldollars_no_name", args); - } - } - else - { - if (dest_id.notNull()) - { - message = success ? LLTrans::getString("you_paid_ldollars_no_reason", args) : - LLTrans::getString("you_paid_failure_ldollars_no_reason", args); - } - else - { - // no target, no reason, you just paid money - message = success ? LLTrans::getString("you_paid_ldollars_no_info", args) : - LLTrans::getString("you_paid_failure_ldollars_no_info", args); - } - } - final_args["MESSAGE"] = message; - payload["dest_id"] = dest_id; - notification = success ? "PaymentSent" : "PaymentFailure"; - } - else - { - // ...someone paid you - if(!gSavedSettings.getBOOL("NotifyMoneyReceived")) - { - return; - } - args["NAME"] = source_slurl; - is_name_group = is_source_group; - name_id = source_id; - - if (!reason.empty() && !LLMuteList::getInstance()->isMuted(source_id)) - { - message = LLTrans::getString("paid_you_ldollars" + gift_suffix, args); - } - else - { - message = LLTrans::getString("paid_you_ldollars_no_reason", args); - } - final_args["MESSAGE"] = message; - - // make notification loggable - payload["from_id"] = source_id; - notification = "PaymentReceived"; - } - - // Despite using SLURLs, wait until the name is available before - // showing the notification, otherwise the UI layout is strange and - // the user sees a "Loading..." message - if (is_name_group) - { - gCacheName->getGroup(name_id, - boost::bind(&money_balance_group_notify, - _1, _2, _3, - notification, final_args, payload)); - } - else - { - LLAvatarNameCache::get(name_id, boost::bind(&money_balance_avatar_notify, _1, _2, notification, final_args, payload)); - } + handle_trusted_experiences_notification(llsdBlock); + return returnValue; } -bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) +bool attempt_standard_notification(LLMessageSystem* msgsystem) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - // set the preference to the maturity of the region we're calling - U8 preferredMaturity = static_cast(notification["payload"]["_region_access"].asInteger()); - gSavedSettings.setU32("PreferredMaturity", static_cast(preferredMaturity)); - } + // if we have additional alert data + if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) + { + // notification was specified using the new mechanism, so we can just handle it here + std::string notificationID; + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + + //SL-13824 skip notification when both joining a group and leaving a group + //remove this after server stops sending these messages + if (notificationID == "JoinGroupSuccess" || + notificationID == "GroupDepart") + { + return true; + } - return false; -} + if (!LLNotifications::getInstance()->templateExists(notificationID)) + { + return false; + } -bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - // set the preference to the maturity of the region we're calling - U8 preferredMaturity = static_cast(notification["payload"]["_region_access"].asInteger()); - gSavedSettings.setU32("PreferredMaturity", static_cast(preferredMaturity)); - gAgent.setMaturityRatingChangeDuringTeleport(preferredMaturity); - gAgent.restartFailedTeleportRequest(); - } - else - { - gAgent.clearTeleportRequest(); - } - - return false; -} + std::string llsdRaw; + LLSD llsdBlock; + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); + if (llsdRaw.length()) + { + std::istringstream llsdData(llsdRaw); + if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length())) + { + LL_WARNS() << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + } + } -// some of the server notifications need special handling. This is where we do that. -bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) -{ - bool returnValue = false; - if(llsdBlock.has("_region_access")) - { - U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - LLNotificationPtr maturityLevelNotification; - std::string notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) - { - if (gAgent.isTeen()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG()) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; - } - } - - if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) - { - // Given a simple notification if no maturityLevelNotification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); - } - } - - return returnValue; -} -bool handle_trusted_experiences_notification(const LLSD& llsdBlock) -{ - if(llsdBlock.has("trusted_experiences")) - { - std::ostringstream str; - const LLSD& experiences = llsdBlock["trusted_experiences"]; - LLSD::array_const_iterator it = experiences.beginArray(); - for(/**/; it != experiences.endArray(); ++it) - { - str<asUUID(), "profile").getSLURLString() << "\n"; - } - std::string str_list = str.str(); - if(!str_list.empty()) - { - LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list)); - return true; - } - } - return false; -} + handle_trusted_experiences_notification(llsdBlock); -// some of the server notifications need special handling. This is where we do that. -bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage) -{ - bool returnValue = false; - if(llsdBlock.has("_region_access")) - { - U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - - LLNotificationPtr tp_failure_notification; - std::string notifySuffix; - - if (notificationID == std::string("TeleportEntryAccessBlocked")) - { - notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) - { - if (gAgent.isTeen()) - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG()) - { - if (gAgent.hasRestartableFailedTeleportRequest()) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - if (gAgent.hasRestartableFailedTeleportRequest()) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - } // End of special handling for "TeleportEntryAccessBlocked" - else - { // Normal case, no message munging - gAgent.clearTeleportRequest(); - if (LLNotifications::getInstance()->templateExists(notificationID)) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); - } - else - { - llsdBlock["MESSAGE"] = defaultMessage; - tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); - } - returnValue = true; - } - - if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored()) - { - // Given a simple notification if no tp_failure_notification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); - } - } - - handle_trusted_experiences_notification(llsdBlock); - return returnValue; -} + if ( + (notificationID == "RegionEntryAccessBlocked") || + (notificationID == "LandClaimAccessBlocked") || + (notificationID == "LandBuyAccessBlocked") -bool attempt_standard_notification(LLMessageSystem* msgsystem) -{ - // if we have additional alert data - if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) - { - // notification was specified using the new mechanism, so we can just handle it here - std::string notificationID; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); - - //SL-13824 skip notification when both joining a group and leaving a group - //remove this after server stops sending these messages - if (notificationID == "JoinGroupSuccess" || - notificationID == "GroupDepart") - { - return true; - } - - if (!LLNotifications::getInstance()->templateExists(notificationID)) - { - return false; - } - - std::string llsdRaw; - LLSD llsdBlock; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); - if (llsdRaw.length()) - { - std::istringstream llsdData(llsdRaw); - if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length())) - { - LL_WARNS() << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; - } - } - - - handle_trusted_experiences_notification(llsdBlock); - - if ( - (notificationID == "RegionEntryAccessBlocked") || - (notificationID == "LandClaimAccessBlocked") || - (notificationID == "LandBuyAccessBlocked") - - ) - { - /*--------------------------------------------------------------------- - (Commented so a grep will find the notification strings, since - we construct them on the fly; if you add additional notifications, - please update the comment.) - - Could throw any of the following notifications: - - RegionEntryAccessBlocked - RegionEntryAccessBlocked_Notify - RegionEntryAccessBlocked_NotifyAdultsOnly - RegionEntryAccessBlocked_Change - RegionEntryAccessBlocked_AdultsOnlyContent - RegionEntryAccessBlocked_ChangeAndReTeleport - LandClaimAccessBlocked - LandClaimAccessBlocked_Notify - LandClaimAccessBlocked_NotifyAdultsOnly - LandClaimAccessBlocked_Change - LandClaimAccessBlocked_AdultsOnlyContent - LandBuyAccessBlocked - LandBuyAccessBlocked_Notify - LandBuyAccessBlocked_NotifyAdultsOnly - LandBuyAccessBlocked_Change - LandBuyAccessBlocked_AdultsOnlyContent - - -----------------------------------------------------------------------*/ + ) + { + /*--------------------------------------------------------------------- + (Commented so a grep will find the notification strings, since + we construct them on the fly; if you add additional notifications, + please update the comment.) + + Could throw any of the following notifications: + + RegionEntryAccessBlocked + RegionEntryAccessBlocked_Notify + RegionEntryAccessBlocked_NotifyAdultsOnly + RegionEntryAccessBlocked_Change + RegionEntryAccessBlocked_AdultsOnlyContent + RegionEntryAccessBlocked_ChangeAndReTeleport + LandClaimAccessBlocked + LandClaimAccessBlocked_Notify + LandClaimAccessBlocked_NotifyAdultsOnly + LandClaimAccessBlocked_Change + LandClaimAccessBlocked_AdultsOnlyContent + LandBuyAccessBlocked + LandBuyAccessBlocked_Notify + LandBuyAccessBlocked_NotifyAdultsOnly + LandBuyAccessBlocked_Change + LandBuyAccessBlocked_AdultsOnlyContent + + -----------------------------------------------------------------------*/ static LLCachedControl ban_lines_mode(gSavedSettings , "ShowBanLines" , LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION); if (ban_lines_mode == LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION) { LLViewerParcelMgr::getInstance()->resetCollisionTimer(); } - if (handle_special_notification(notificationID, llsdBlock)) - { - return true; - } - } - // HACK -- handle callbacks for specific alerts. - if( notificationID == "HomePositionSet" ) - { - // save the home location image to disk - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenHomeFilename(); + if (handle_special_notification(notificationID, llsdBlock)) + { + return true; + } + } + // HACK -- handle callbacks for specific alerts. + if( notificationID == "HomePositionSet" ) + { + // save the home location image to disk + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenHomeFilename(); gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), @@ -5222,44 +5222,44 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - } - - if (notificationID == "RegionRestartMinutes" || - notificationID == "RegionRestartSeconds") - { - S32 seconds; - if (notificationID == "RegionRestartMinutes") - { - seconds = 60 * static_cast(llsdBlock["MINUTES"].asInteger()); - } - else - { - seconds = static_cast(llsdBlock["SECONDS"].asInteger()); - } - - LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance("region_restarting"); - - if (floaterp) - { - LLFloaterRegionRestarting::updateTime(seconds); - } - else - { - LLSD params; - params["NAME"] = llsdBlock["NAME"]; - params["SECONDS"] = (LLSD::Integer)seconds; - LLFloaterRegionRestarting* restarting_floater = dynamic_cast(LLFloaterReg::showInstance("region_restarting", params)); - if(restarting_floater) - { - restarting_floater->center(); - } - } - - make_ui_sound("UISndRestart"); - } - + } + + if (notificationID == "RegionRestartMinutes" || + notificationID == "RegionRestartSeconds") + { + S32 seconds; + if (notificationID == "RegionRestartMinutes") + { + seconds = 60 * static_cast(llsdBlock["MINUTES"].asInteger()); + } + else + { + seconds = static_cast(llsdBlock["SECONDS"].asInteger()); + } + + LLFloaterRegionRestarting* floaterp = LLFloaterReg::findTypedInstance("region_restarting"); + + if (floaterp) + { + LLFloaterRegionRestarting::updateTime(seconds); + } + else + { + LLSD params; + params["NAME"] = llsdBlock["NAME"]; + params["SECONDS"] = (LLSD::Integer)seconds; + LLFloaterRegionRestarting* restarting_floater = dynamic_cast(LLFloaterReg::showInstance("region_restarting", params)); + if(restarting_floater) + { + restarting_floater->center(); + } + } + + make_ui_sound("UISndRestart"); + } + // Special Marketplace update notification - if (notificationID == "SLM_UPDATE_FOLDER") + if (notificationID == "SLM_UPDATE_FOLDER") { std::string state = llsdBlock["state"].asString(); if (state == "deleted") @@ -5298,28 +5298,28 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } - LLNotificationsUtil::add(notificationID, llsdBlock); - return true; - } - return false; + LLNotificationsUtil::add(notificationID, llsdBlock); + return true; + } + return false; } static void process_special_alert_messages(const std::string & message) { - // Do special handling for alert messages. This is a legacy hack, and any actual displayed - // text should be altered in the notifications.xml files. - if ( message == "You died and have been teleported to your home location") - { - add(LLStatViewer::KILLED, 1); - } - else if( message == "Home position set." ) - { - // save the home location image to disk - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += LLStartUp::getScreenHomeFilename(); - gViewerWindow->saveSnapshot(snap_filename, + // Do special handling for alert messages. This is a legacy hack, and any actual displayed + // text should be altered in the notifications.xml files. + if ( message == "You died and have been teleported to your home location") + { + add(LLStatViewer::KILLED, 1); + } + else if( message == "Home position set." ) + { + // save the home location image to disk + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += LLStartUp::getScreenHomeFilename(); + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, @@ -5327,28 +5327,28 @@ static void process_special_alert_messages(const std::string & message) FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); - } + } } void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) { - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - std::string message; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); - process_special_alert_messages(message); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + + process_special_alert_messages(message); - if (!attempt_standard_notification(msgsystem)) - { - BOOL modal = FALSE; - msgsystem->getBOOL("AlertData", "Modal", modal); - process_alert_core(message, modal); - } + if (!attempt_standard_notification(msgsystem)) + { + BOOL modal = FALSE; + msgsystem->getBOOL("AlertData", "Modal", modal); + process_alert_core(message, modal); + } } // The only difference between this routine and the previous is the fact that @@ -5358,18 +5358,18 @@ void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) // So we can't handle the messages with the same handler. void process_alert_message(LLMessageSystem *msgsystem, void **user_data) { - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - std::string message; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); - process_special_alert_messages(message); + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); - if (!attempt_standard_notification(msgsystem)) - { - BOOL modal = FALSE; - process_alert_core(message, modal); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + process_special_alert_messages(message); + + if (!attempt_standard_notification(msgsystem)) + { + BOOL modal = FALSE; + process_alert_core(message, modal); static LLCachedControl ban_lines_mode(gSavedSettings , "ShowBanLines" , LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION); if (ban_lines_mode == LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION @@ -5377,289 +5377,289 @@ void process_alert_message(LLMessageSystem *msgsystem, void **user_data) { LLViewerParcelMgr::getInstance()->resetCollisionTimer(); } - } + } } bool handle_not_age_verified_alert(const std::string &pAlertName) { - LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); - if ((notification == NULL) || notification->isIgnored()) - { - LLNotificationsUtil::add(pAlertName + "_Notify"); - } + LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); + if ((notification == NULL) || notification->isIgnored()) + { + LLNotificationsUtil::add(pAlertName + "_Notify"); + } - return true; + return true; } bool handle_special_alerts(const std::string &pAlertName) { - bool isHandled = false; - if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) - { - - isHandled = handle_not_age_verified_alert(pAlertName); - } + bool isHandled = false; + if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) + { + + isHandled = handle_not_age_verified_alert(pAlertName); + } - return isHandled; + return isHandled; } void process_alert_core(const std::string& message, BOOL modal) { - const std::string ALERT_PREFIX("ALERT: "); - const std::string NOTIFY_PREFIX("NOTIFY: "); - if (message.find(ALERT_PREFIX) == 0) - { - // Allow the server to spawn a named alert so that server alerts can be - // translated out of English. - std::string alert_name(message.substr(ALERT_PREFIX.length())); - if (!handle_special_alerts(alert_name)) - { - LLNotificationsUtil::add(alert_name); - } - } - else if (message.find(NOTIFY_PREFIX) == 0) - { - // Allow the server to spawn a named notification so that server notifications can be - // translated out of English. - std::string notify_name(message.substr(NOTIFY_PREFIX.length())); - LLNotificationsUtil::add(notify_name); - } - else if (message[0] == '/') - { - // System message is important, show in upper-right box not tip - std::string text(message.substr(1)); - LLSD args; - - // *NOTE: If the text from the server ever changes this line will need to be adjusted. - std::string restart_cancelled = "Region restart cancelled."; - if (text.substr(0, restart_cancelled.length()) == restart_cancelled) - { - LLFloaterRegionRestarting::close(); - } - - std::string new_msg =LLNotifications::instance().getGlobalString(text); - args["MESSAGE"] = new_msg; - LLNotificationsUtil::add("SystemMessage", args); - } - else if (modal) - { - LLSD args; - std::string new_msg =LLNotifications::instance().getGlobalString(message); - args["ERROR_MESSAGE"] = new_msg; - LLNotificationsUtil::add("ErrorMessage", args); - } - else - { - // Hack fix for EXP-623 (blame fix on RN :)) to avoid a sim deploy - const std::string AUTOPILOT_CANCELED_MSG("Autopilot canceled"); - if (message.find(AUTOPILOT_CANCELED_MSG) == std::string::npos ) - { - LLSD args; - std::string new_msg =LLNotifications::instance().getGlobalString(message); - - std::string localized_msg; - bool is_message_localized = LLTrans::findString(localized_msg, new_msg); - - args["MESSAGE"] = is_message_localized ? localized_msg : new_msg; - LLNotificationsUtil::add("SystemMessageTip", args); - } - } -} - -mean_collision_list_t gMeanCollisionList; -time_t gLastDisplayedTime = 0; + const std::string ALERT_PREFIX("ALERT: "); + const std::string NOTIFY_PREFIX("NOTIFY: "); + if (message.find(ALERT_PREFIX) == 0) + { + // Allow the server to spawn a named alert so that server alerts can be + // translated out of English. + std::string alert_name(message.substr(ALERT_PREFIX.length())); + if (!handle_special_alerts(alert_name)) + { + LLNotificationsUtil::add(alert_name); + } + } + else if (message.find(NOTIFY_PREFIX) == 0) + { + // Allow the server to spawn a named notification so that server notifications can be + // translated out of English. + std::string notify_name(message.substr(NOTIFY_PREFIX.length())); + LLNotificationsUtil::add(notify_name); + } + else if (message[0] == '/') + { + // System message is important, show in upper-right box not tip + std::string text(message.substr(1)); + LLSD args; + + // *NOTE: If the text from the server ever changes this line will need to be adjusted. + std::string restart_cancelled = "Region restart cancelled."; + if (text.substr(0, restart_cancelled.length()) == restart_cancelled) + { + LLFloaterRegionRestarting::close(); + } + + std::string new_msg =LLNotifications::instance().getGlobalString(text); + args["MESSAGE"] = new_msg; + LLNotificationsUtil::add("SystemMessage", args); + } + else if (modal) + { + LLSD args; + std::string new_msg =LLNotifications::instance().getGlobalString(message); + args["ERROR_MESSAGE"] = new_msg; + LLNotificationsUtil::add("ErrorMessage", args); + } + else + { + // Hack fix for EXP-623 (blame fix on RN :)) to avoid a sim deploy + const std::string AUTOPILOT_CANCELED_MSG("Autopilot canceled"); + if (message.find(AUTOPILOT_CANCELED_MSG) == std::string::npos ) + { + LLSD args; + std::string new_msg =LLNotifications::instance().getGlobalString(message); + + std::string localized_msg; + bool is_message_localized = LLTrans::findString(localized_msg, new_msg); + + args["MESSAGE"] = is_message_localized ? localized_msg : new_msg; + LLNotificationsUtil::add("SystemMessageTip", args); + } + } +} + +mean_collision_list_t gMeanCollisionList; +time_t gLastDisplayedTime = 0; void handle_show_mean_events(void *) { - LLFloaterReg::showInstance("bumps"); - //LLFloaterBump::showInstance(); + LLFloaterReg::showInstance("bumps"); + //LLFloaterBump::showInstance(); } void mean_name_callback(const LLUUID &id, const LLAvatarName& av_name) { - static const U32 max_collision_list_size = 20; - if (gMeanCollisionList.size() > max_collision_list_size) - { - mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (U32 i=0; imPerp == id) - { - mcd->mFullName = av_name.getUserName(); - } - } + static const U32 max_collision_list_size = 20; + if (gMeanCollisionList.size() > max_collision_list_size) + { + mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); + for (U32 i=0; imPerp == id) + { + mcd->mFullName = av_name.getUserName(); + } + } } void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data) { - if (gAgent.inPrelude()) - { - // In prelude, bumping is OK. This dialog is rather confusing to - // newbies, so we don't show it. Drop the packet on the floor. - return; - } - - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - LLUUID perp; - U32 time; - U8 u8type; - EMeanCollisionType type; - F32 mag; - - S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision); - - for (i = 0; i < num; i++) - { - msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp); - msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time); - msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag); - msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type); - - type = (EMeanCollisionType)u8type; - - BOOL b_found = FALSE; - - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) - { - LLMeanCollisionData *mcd = *iter; - if ((mcd->mPerp == perp) && (mcd->mType == type)) - { - mcd->mTime = time; - mcd->mMag = mag; - b_found = TRUE; - break; - } - } - - if (!b_found) - { - LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); - gMeanCollisionList.push_front(mcd); - LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); - } - } - LLFloaterBump* bumps_floater = LLFloaterBump::getInstance(); - if(bumps_floater && bumps_floater->isInVisibleChain()) - { - bumps_floater->populateCollisionList(); - } + if (gAgent.inPrelude()) + { + // In prelude, bumping is OK. This dialog is rather confusing to + // newbies, so we don't show it. Drop the packet on the floor. + return; + } + + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); + + LLUUID perp; + U32 time; + U8 u8type; + EMeanCollisionType type; + F32 mag; + + S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision); + + for (i = 0; i < num; i++) + { + msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp); + msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time); + msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag); + msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type); + + type = (EMeanCollisionType)u8type; + + BOOL b_found = FALSE; + + for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); + iter != gMeanCollisionList.end(); ++iter) + { + LLMeanCollisionData *mcd = *iter; + if ((mcd->mPerp == perp) && (mcd->mType == type)) + { + mcd->mTime = time; + mcd->mMag = mag; + b_found = TRUE; + break; + } + } + + if (!b_found) + { + LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); + gMeanCollisionList.push_front(mcd); + LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); + } + } + LLFloaterBump* bumps_floater = LLFloaterBump::getInstance(); + if(bumps_floater && bumps_floater->isInVisibleChain()) + { + bumps_floater->populateCollisionList(); + } } void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) { - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - BOOL b_frozen; - - msgsystem->getBOOL("FrozenData", "Data", b_frozen); + // make sure the cursor is back to the usual default since the + // alert is probably due to some kind of error. + gViewerWindow->getWindow()->resetBusyCount(); + BOOL b_frozen; + + msgsystem->getBOOL("FrozenData", "Data", b_frozen); - // TODO: make being frozen change view - if (b_frozen) - { - } - else - { - } + // TODO: make being frozen change view + if (b_frozen) + { + } + else + { + } } // do some extra stuff once we get our economy data void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) { - LL_DEBUGS("Benefits") << "Received economy data, not currently used" << LL_ENDL; + LL_DEBUGS("Benefits") << "Received economy data, not currently used" << LL_ENDL; } void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) { - // only continue if at least some permissions were requested - if (orig_questions) - { - // check to see if the person we are asking - - // "'[OBJECTNAME]', an object owned by '[OWNERNAME]', - // located in [REGIONNAME] at [REGIONPOS], - // has been permission to: [PERMISSIONS]." - - LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); - - // always include the object name and owner name - notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); - notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString()); - - // try to lookup viewerobject that corresponds to the object that - // requested permissions (here, taskid->requesting object id) - BOOL foundpos = FALSE; - LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); - if (viewobj) - { - // found the viewerobject, get it's position in its region - LLVector3 objpos(viewobj->getPosition()); - - // try to lookup the name of the region the object is in - LLViewerRegion* viewregion = viewobj->getRegion(); - if (viewregion) - { - // got the region, so include the region and 3d coordinates of the object - notice.setArg("[REGIONNAME]", viewregion->getName()); - std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); - notice.setArg("[REGIONPOS]", formatpos); - - foundpos = TRUE; - } - } - - if (!foundpos) - { - // unable to determine location of the object - notice.setArg("[REGIONNAME]", "(unknown region)"); - notice.setArg("[REGIONPOS]", "(unknown position)"); - } - - // check each permission that was requested, and list each - // permission that has been flagged as a caution permission - BOOL caution = FALSE; - S32 count = 0; - std::string perms; - for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) - { - if ((orig_questions & script_perm.permbit) - && script_perm.caution) - { - count++; - caution = TRUE; - - // add a comma before the permission description if it is not the first permission - // added to the list or the last permission to check - if (count > 1) - { - perms.append(", "); - } - - perms.append(LLTrans::getString(script_perm.question)); - } - } - - notice.setArg("[PERMISSIONS]", perms); - - // log a chat message as long as at least one requested permission - // is a caution permission - if (caution) - { - LLChat chat(notice.getString()); - // LLFloaterChat::addChat(chat, FALSE, FALSE); - } - } + // only continue if at least some permissions were requested + if (orig_questions) + { + // check to see if the person we are asking + + // "'[OBJECTNAME]', an object owned by '[OWNERNAME]', + // located in [REGIONNAME] at [REGIONPOS], + // has been permission to: [PERMISSIONS]." + + LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); + + // always include the object name and owner name + notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); + notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString()); + + // try to lookup viewerobject that corresponds to the object that + // requested permissions (here, taskid->requesting object id) + BOOL foundpos = FALSE; + LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); + if (viewobj) + { + // found the viewerobject, get it's position in its region + LLVector3 objpos(viewobj->getPosition()); + + // try to lookup the name of the region the object is in + LLViewerRegion* viewregion = viewobj->getRegion(); + if (viewregion) + { + // got the region, so include the region and 3d coordinates of the object + notice.setArg("[REGIONNAME]", viewregion->getName()); + std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); + notice.setArg("[REGIONPOS]", formatpos); + + foundpos = TRUE; + } + } + + if (!foundpos) + { + // unable to determine location of the object + notice.setArg("[REGIONNAME]", "(unknown region)"); + notice.setArg("[REGIONPOS]", "(unknown position)"); + } + + // check each permission that was requested, and list each + // permission that has been flagged as a caution permission + BOOL caution = FALSE; + S32 count = 0; + std::string perms; + for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) + { + if ((orig_questions & script_perm.permbit) + && script_perm.caution) + { + count++; + caution = TRUE; + + // add a comma before the permission description if it is not the first permission + // added to the list or the last permission to check + if (count > 1) + { + perms.append(", "); + } + + perms.append(LLTrans::getString(script_perm.question)); + } + } + + notice.setArg("[PERMISSIONS]", perms); + + // log a chat message as long as at least one requested permission + // is a caution permission + if (caution) + { + LLChat chat(notice.getString()); + // LLFloaterChat::addChat(chat, FALSE, FALSE); + } + } } void script_question_mute(const LLUUID& item_id, const std::string& object_name); @@ -5676,97 +5676,97 @@ void experiencePermissionBlock(LLUUID experience, LLSD result) bool script_question_cb(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem *msg = gMessageSystem; - S32 orig = notification["payload"]["questions"].asInteger(); - S32 new_questions = orig; - - if (response["Details"]) - { - // respawn notification... - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); - - // ...with description on top - LLNotificationsUtil::add("DebitPermissionDetails"); - return false; - } - - LLUUID experience; - if(notification["payload"].has("experience")) - { - experience = notification["payload"]["experience"].asUUID(); - } - - // check whether permissions were granted or denied - BOOL allowed = TRUE; - // the "yes/accept" button is the first button in the template, making it button 0 - // if any other button was clicked, the permissions were denied - if (option != 0) - { - new_questions = 0; - allowed = FALSE; - } - else if(experience.notNull()) - { - LLSD permission; - LLSD data; - permission["permission"]="Allow"; - - data[experience.asString()]=permission; - data["experience"]=experience; - LLEventPumps::instance().obtain("experience_permission").post(data); - } - - LLUUID task_id = notification["payload"]["task_id"].asUUID(); - LLUUID item_id = notification["payload"]["item_id"].asUUID(); - - // reply with the permissions granted or denied - msg->newMessageFast(_PREHASH_ScriptAnswerYes); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_TaskID, task_id); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - msg->addS32Fast(_PREHASH_Questions, new_questions); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - - // only log a chat message if caution prompts are enabled - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - // log a chat message, if appropriate - notify_cautioned_script_question(notification, response, orig, allowed); - } - - if ( response["Mute"] ) // mute - { - script_question_mute(task_id,notification["payload"]["object_name"].asString()); - } - if ( response["BlockExperience"] ) - { - if(experience.notNull()) - { - LLViewerRegion* region = gAgent.getRegion(); - if (!region) - return false; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLMessageSystem *msg = gMessageSystem; + S32 orig = notification["payload"]["questions"].asInteger(); + S32 new_questions = orig; + + if (response["Details"]) + { + // respawn notification... + LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); + + // ...with description on top + LLNotificationsUtil::add("DebitPermissionDetails"); + return false; + } + + LLUUID experience; + if(notification["payload"].has("experience")) + { + experience = notification["payload"]["experience"].asUUID(); + } + + // check whether permissions were granted or denied + BOOL allowed = TRUE; + // the "yes/accept" button is the first button in the template, making it button 0 + // if any other button was clicked, the permissions were denied + if (option != 0) + { + new_questions = 0; + allowed = FALSE; + } + else if(experience.notNull()) + { + LLSD permission; + LLSD data; + permission["permission"]="Allow"; + + data[experience.asString()]=permission; + data["experience"]=experience; + LLEventPumps::instance().obtain("experience_permission").post(data); + } + + LLUUID task_id = notification["payload"]["task_id"].asUUID(); + LLUUID item_id = notification["payload"]["item_id"].asUUID(); + + // reply with the permissions granted or denied + msg->newMessageFast(_PREHASH_ScriptAnswerYes); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Data); + msg->addUUIDFast(_PREHASH_TaskID, task_id); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->addS32Fast(_PREHASH_Questions, new_questions); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + + // only log a chat message if caution prompts are enabled + if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) + { + // log a chat message, if appropriate + notify_cautioned_script_question(notification, response, orig, allowed); + } + + if ( response["Mute"] ) // mute + { + script_question_mute(task_id,notification["payload"]["object_name"].asString()); + } + if ( response["BlockExperience"] ) + { + if(experience.notNull()) + { + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return false; LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), boost::bind(&experiencePermissionBlock, experience, _1)); - } + } } - return false; + return false; } void script_question_mute(const LLUUID& task_id, const std::string& object_name) { - LLMuteList::getInstance()->add(LLMute(task_id, object_name, LLMute::OBJECT)); + LLMuteList::getInstance()->add(LLMute(task_id, object_name, LLMute::OBJECT)); // purge the message queue of any previously queued requests from the same source. DEV-4879 class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher { public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} + bool matches(const LLNotificationPtr notification) const { if (notification->getName() == "ScriptQuestionCaution" || notification->getName() == "ScriptQuestion") @@ -5789,178 +5789,178 @@ static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestio void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload) { - if(experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID) - { - args["GRID_WIDE"] = LLTrans::getString("Grid-Scope"); - } - else - { - args["GRID_WIDE"] = LLTrans::getString("Land-Scope"); - } - args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString(); + if(experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID) + { + args["GRID_WIDE"] = LLTrans::getString("Grid-Scope"); + } + else + { + args["GRID_WIDE"] = LLTrans::getString("Land-Scope"); + } + args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString(); - LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); + LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); } void process_script_question(LLMessageSystem *msg, void **user_data) { - // *TODO: Translate owner name -> [FIRST] [LAST] - - LLHost sender = msg->getSender(); - - LLUUID taskid; - LLUUID itemid; - S32 questions; - std::string object_name; - std::string owner_name; - LLUUID experienceid; - - // taskid -> object key of object requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); - // itemid -> script asset key of script requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); - msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); - msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); - - if(msg->has(_PREHASH_Experience)) - { - msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid); - } - - // Special case. If the objects are owned by this agent, throttle per-object instead - // of per-owner. It's common for residents to reset a ton of scripts that re-request - // permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa, - // so we'll reuse the same namespace for both throttle types. - std::string throttle_name = owner_name; - std::string self_name; - LLAgentUI::buildFullname( self_name ); // does not include ' Resident' - std::string clean_owner_name = LLCacheName::cleanFullName(owner_name); // removes ' Resident' - if( clean_owner_name == self_name ) - { - throttle_name = taskid.getString(); - } - - // don't display permission requests if this object is muted - if (LLMuteList::getInstance()->isMuted(taskid)) return; - - // throttle excessive requests from any specific user's scripts - typedef LLKeyThrottle LLStringThrottle; - static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); - - switch (question_throttle.noteAction(throttle_name)) - { - case LLStringThrottle::THROTTLE_NEWLY_BLOCKED: - LL_INFOS("Messaging") << "process_script_question throttled" - << " owner_name:" << owner_name - << LL_ENDL; - // Fall through - - case LLStringThrottle::THROTTLE_BLOCKED: - // Escape altogether until we recover - return; - - case LLStringThrottle::THROTTLE_OK: - break; - } - - std::string script_question; - if (questions) - { - bool caution = false; - S32 count = 0; - LLSD args; - args["OBJECTNAME"] = object_name; - args["NAME"] = clean_owner_name; - S32 known_questions = 0; - bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; - // check the received permission flags against each permission - for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) - { - if (questions & script_perm.permbit) - { - count++; - known_questions |= script_perm.permbit; - // check whether permission question should cause special caution dialog - caution |= (script_perm.caution); - - if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) - continue; + // *TODO: Translate owner name -> [FIRST] [LAST] + + LLHost sender = msg->getSender(); + + LLUUID taskid; + LLUUID itemid; + S32 questions; + std::string object_name; + std::string owner_name; + LLUUID experienceid; + + // taskid -> object key of object requesting permissions + msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); + // itemid -> script asset key of script requesting permissions + msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); + msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); + msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); + + if(msg->has(_PREHASH_Experience)) + { + msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid); + } + + // Special case. If the objects are owned by this agent, throttle per-object instead + // of per-owner. It's common for residents to reset a ton of scripts that re-request + // permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa, + // so we'll reuse the same namespace for both throttle types. + std::string throttle_name = owner_name; + std::string self_name; + LLAgentUI::buildFullname( self_name ); // does not include ' Resident' + std::string clean_owner_name = LLCacheName::cleanFullName(owner_name); // removes ' Resident' + if( clean_owner_name == self_name ) + { + throttle_name = taskid.getString(); + } + + // don't display permission requests if this object is muted + if (LLMuteList::getInstance()->isMuted(taskid)) return; + + // throttle excessive requests from any specific user's scripts + typedef LLKeyThrottle LLStringThrottle; + static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); + + switch (question_throttle.noteAction(throttle_name)) + { + case LLStringThrottle::THROTTLE_NEWLY_BLOCKED: + LL_INFOS("Messaging") << "process_script_question throttled" + << " owner_name:" << owner_name + << LL_ENDL; + // Fall through + + case LLStringThrottle::THROTTLE_BLOCKED: + // Escape altogether until we recover + return; + + case LLStringThrottle::THROTTLE_OK: + break; + } + + std::string script_question; + if (questions) + { + bool caution = false; + S32 count = 0; + LLSD args; + args["OBJECTNAME"] = object_name; + args["NAME"] = clean_owner_name; + S32 known_questions = 0; + bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; + // check the received permission flags against each permission + for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) + { + if (questions & script_perm.permbit) + { + count++; + known_questions |= script_perm.permbit; + // check whether permission question should cause special caution dialog + caution |= (script_perm.caution); + + if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) + continue; if (LLTrans::getString(script_perm.question).empty()) { continue; } - script_question += " " + LLTrans::getString(script_perm.question) + "\n"; - } - } - - args["QUESTIONS"] = script_question; - - if (known_questions != questions) - { - // This is in addition to the normal dialog. - // Viewer got a request for not supported/implemented permission - LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question - << " permission. Permission is unknown and can't be granted. Item id: " << itemid - << " taskid:" << taskid << LL_ENDL; - } - - if (known_questions) - { - LLSD payload; - payload["task_id"] = taskid; - payload["item_id"] = itemid; - payload["sender"] = sender.getIPandPort(); - payload["questions"] = known_questions; - payload["object_name"] = object_name; - payload["owner_name"] = owner_name; - - // check whether cautions are even enabled or not - const char* notification = "ScriptQuestion"; - - if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : ""; - notification = "ScriptQuestionCaution"; - } - else if(experienceid.notNull()) - { - payload["experience"]=experienceid; + script_question += " " + LLTrans::getString(script_perm.question) + "\n"; + } + } + + args["QUESTIONS"] = script_question; + + if (known_questions != questions) + { + // This is in addition to the normal dialog. + // Viewer got a request for not supported/implemented permission + LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question + << " permission. Permission is unknown and can't be granted. Item id: " << itemid + << " taskid:" << taskid << LL_ENDL; + } + + if (known_questions) + { + LLSD payload; + payload["task_id"] = taskid; + payload["item_id"] = itemid; + payload["sender"] = sender.getIPandPort(); + payload["questions"] = known_questions; + payload["object_name"] = object_name; + payload["owner_name"] = owner_name; + + // check whether cautions are even enabled or not + const char* notification = "ScriptQuestion"; + + if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) + { + args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : ""; + notification = "ScriptQuestionCaution"; + } + else if(experienceid.notNull()) + { + payload["experience"]=experienceid; LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); - return; - } + return; + } - LLNotificationsUtil::add(notification, args, payload); - } - } + LLNotificationsUtil::add(notification, args, payload); + } + } } void process_derez_container(LLMessageSystem *msg, void**) { - LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; + LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; } void container_inventory_arrived(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void* data) -{ - LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - } - - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - - if (inventory->size() > 2) - { - // create a new inventory category to put this in - LLUUID cat_id; - gInventory.createNewCategory( + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* data) +{ + LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; + if( gAgentCamera.cameraMouselook() ) + { + gAgentCamera.changeCameraToDefault(); + } + + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + + if (inventory->size() > 2) + { + // create a new inventory category to put this in + LLUUID cat_id; + gInventory.createNewCategory( gInventory.getRootFolderID(), LLFolderType::FT_NONE, LLTrans::getString("AcquiredItems"), @@ -6001,532 +6001,532 @@ void container_inventory_arrived(LLViewerObject* object, active_panel->setSelection(new_cat_id, TAKE_FOCUS_NO); } }); - } - else if (inventory->size() == 2) - { - // we're going to get one fake root category as well as the - // one actual object - LLInventoryObject::object_list_t::iterator it = inventory->begin(); - - if ((*it)->getType() == LLAssetType::AT_CATEGORY) - { - ++it; - } - - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); - - LLUUID item_id; - item_id.generate(); - time_t creation_date_utc = time_corrected(); - LLPointer new_item - = new LLViewerInventoryItem(item_id, category, - item->getPermissions(), - item->getAssetUUID(), - item->getType(), - item->getInventoryType(), - item->getName(), - item->getDescription(), - LLSaleInfo::DEFAULT, - item->getFlags(), - creation_date_utc); - new_item->updateServer(TRUE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - if(active_panel) - { - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - } - } - - // we've got the inventory, now delete this object if this was a take - BOOL delete_object = (BOOL)(intptr_t)data; - LLViewerRegion *region = gAgent.getRegion(); - if (delete_object && region) - { - gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - const U8 NO_FORCE = 0; - gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - gMessageSystem->sendReliable(region->getHost()); - } + } + else if (inventory->size() == 2) + { + // we're going to get one fake root category as well as the + // one actual object + LLInventoryObject::object_list_t::iterator it = inventory->begin(); + + if ((*it)->getType() == LLAssetType::AT_CATEGORY) + { + ++it; + } + + LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); + const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); + + LLUUID item_id; + item_id.generate(); + time_t creation_date_utc = time_corrected(); + LLPointer new_item + = new LLViewerInventoryItem(item_id, category, + item->getPermissions(), + item->getAssetUUID(), + item->getType(), + item->getInventoryType(), + item->getName(), + item->getDescription(), + LLSaleInfo::DEFAULT, + item->getFlags(), + creation_date_utc); + new_item->updateServer(TRUE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + if(active_panel) + { + active_panel->setSelection(item_id, TAKE_FOCUS_NO); + } + } + + // we've got the inventory, now delete this object if this was a take + BOOL delete_object = (BOOL)(intptr_t)data; + LLViewerRegion *region = gAgent.getRegion(); + if (delete_object && region) + { + gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + const U8 NO_FORCE = 0; + gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); + gMessageSystem->sendReliable(region->getHost()); + } } // method to format the time. std::string formatted_time(const time_t& the_time) { - std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] [" - +LLTrans::getString("LTimeMonth")+"] [" - +LLTrans::getString("LTimeDay")+"] [" - +LLTrans::getString("LTimeHour")+"]:[" - +LLTrans::getString("LTimeMin")+"]:[" - +LLTrans::getString("LTimeSec")+"] [" - +LLTrans::getString("LTimeYear")+"]"; + std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] [" + +LLTrans::getString("LTimeMonth")+"] [" + +LLTrans::getString("LTimeDay")+"] [" + +LLTrans::getString("LTimeHour")+"]:[" + +LLTrans::getString("LTimeMin")+"]:[" + +LLTrans::getString("LTimeSec")+"] [" + +LLTrans::getString("LTimeYear")+"]"; - LLSD substitution; - substitution["datetime"] = (S32) the_time; - LLStringUtil::format (dateStr, substitution); - return dateStr; + LLSD substitution; + substitution["datetime"] = (S32) the_time; + LLStringUtil::format (dateStr, substitution); + return dateStr; } void process_teleport_failed(LLMessageSystem *msg, void**) { - LL_WARNS("Teleport","Messaging") << "Received TeleportFailed message" << LL_ENDL; - - std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" - std::string big_reason; // Actual message to display - LLSD args; - - // Let the interested parties know that teleport failed. - LLViewerParcelMgr::getInstance()->onTeleportFailed(); - - // if we have additional alert data - if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) - { - // Get the message ID - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); - big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() <= 0 ) - { - // Nothing found in the map - use what the server returned in the original message block - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); - } - LL_WARNS("Teleport") << "AlertInfo message_id " << message_id << " reason: " << big_reason << LL_ENDL; - - LLSD llsd_block; - std::string llsd_raw; - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); - if (llsd_raw.length()) - { - std::istringstream llsd_data(llsd_raw); - if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) - { - LL_WARNS("Teleport") << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; - } - else - { - LL_WARNS("Teleport") << "AlertInfo llsd block received: " << llsd_block << LL_ENDL; - if(llsd_block.has("REGION_NAME")) - { - std::string region_name = llsd_block["REGION_NAME"].asString(); - if(!region_name.empty()) - { - LLStringUtil::format_map_t name_args; - name_args["[REGION_NAME]"] = region_name; - LLStringUtil::format(big_reason, name_args); - } - } - // change notification name in this special case - if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) - { - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - LL_WARNS("Teleport") << "called handle_teleport_access_blocked, setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - return; - } - } - } - args["REASON"] = big_reason; - } - else - { // Extra message payload not found - use what the simulator sent - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); - - big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() > 0 ) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned - args["REASON"] = message_id; - } - } - LL_WARNS("Teleport") << "Displaying CouldNotTeleportReason string, REASON= " << args["REASON"] << LL_ENDL; - - LLNotificationsUtil::add("CouldNotTeleportReason", args); - - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - LL_WARNS("Teleport") << "End of process_teleport_failed(). Reason message arg is " << args["REASON"] - << ". Setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } + LL_WARNS("Teleport","Messaging") << "Received TeleportFailed message" << LL_ENDL; + + std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" + std::string big_reason; // Actual message to display + LLSD args; + + // Let the interested parties know that teleport failed. + LLViewerParcelMgr::getInstance()->onTeleportFailed(); + + // if we have additional alert data + if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) + { + // Get the message ID + msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); + big_reason = LLAgent::sTeleportErrorMessages[message_id]; + if ( big_reason.size() <= 0 ) + { + // Nothing found in the map - use what the server returned in the original message block + msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); + } + LL_WARNS("Teleport") << "AlertInfo message_id " << message_id << " reason: " << big_reason << LL_ENDL; + + LLSD llsd_block; + std::string llsd_raw; + msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); + if (llsd_raw.length()) + { + std::istringstream llsd_data(llsd_raw); + if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) + { + LL_WARNS("Teleport") << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; + } + else + { + LL_WARNS("Teleport") << "AlertInfo llsd block received: " << llsd_block << LL_ENDL; + if(llsd_block.has("REGION_NAME")) + { + std::string region_name = llsd_block["REGION_NAME"].asString(); + if(!region_name.empty()) + { + LLStringUtil::format_map_t name_args; + name_args["[REGION_NAME]"] = region_name; + LLStringUtil::format(big_reason, name_args); + } + } + // change notification name in this special case + if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) + { + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + { + LL_WARNS("Teleport") << "called handle_teleport_access_blocked, setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } + return; + } + } + } + args["REASON"] = big_reason; + } + else + { // Extra message payload not found - use what the simulator sent + msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); + + big_reason = LLAgent::sTeleportErrorMessages[message_id]; + if ( big_reason.size() > 0 ) + { // Substitute verbose reason from the local map + args["REASON"] = big_reason; + } + else + { // Nothing found in the map - use what the server returned + args["REASON"] = message_id; + } + } + LL_WARNS("Teleport") << "Displaying CouldNotTeleportReason string, REASON= " << args["REASON"] << LL_ENDL; + + LLNotificationsUtil::add("CouldNotTeleportReason", args); + + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + { + LL_WARNS("Teleport") << "End of process_teleport_failed(). Reason message arg is " << args["REASON"] + << ". Setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } } void process_teleport_local(LLMessageSystem *msg,void**) { - LL_INFOS("Teleport","Messaging") << "Received TeleportLocal message" << LL_ENDL; - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Teleport", "Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; - return; - } - - U32 location_id; - LLVector3 pos, look_at; - U32 teleport_flags; - msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); - msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); - msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); - msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - LL_INFOS("Teleport") << "Message params are location_id " << location_id << " teleport_flags " << teleport_flags << LL_ENDL; - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) - { - // To prevent TeleportStart messages re-activating the progress screen right - // after tp, keep the teleport state and let progress screen clear it after a short delay - // (progress screen is active but not visible) *TODO: remove when SVC-5290 is fixed - gTeleportDisplayTimer.reset(); - gTeleportDisplay = TRUE; - } - else - { - LL_WARNS("Teleport") << "State is not TELEPORT_LOCAL: " << gAgent.getTeleportStateName() - << ", setting state to TELEPORT_NONE" << LL_ENDL; - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - } - - // Sim tells us whether the new position is off the ground - if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) - { - gAgent.setFlying(TRUE); - } - else - { - gAgent.setFlying(FALSE); - } - - gAgent.setPositionAgent(pos); - gAgentCamera.slamLookAt(look_at); - - if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) ) - { - gAgentCamera.resetView(TRUE, TRUE); - } - - // send camera update to new region - gAgentCamera.updateCamera(); - - send_agent_update(TRUE, TRUE); - - // Let the interested parties know we've teleported. - // Vadim *HACK: Agent position seems to get reset (to render position?) - // on each frame, so we have to pass the new position manually. - LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos)); + LL_INFOS("Teleport","Messaging") << "Received TeleportLocal message" << LL_ENDL; + + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS("Teleport", "Messaging") << "Got teleport notification for wrong agent " << agent_id << " expected " << gAgent.getID() << ", ignoring!" << LL_ENDL; + return; + } + + U32 location_id; + LLVector3 pos, look_at; + U32 teleport_flags; + msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); + msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); + msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); + msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + + LL_INFOS("Teleport") << "Message params are location_id " << location_id << " teleport_flags " << teleport_flags << LL_ENDL; + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + { + if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) + { + // To prevent TeleportStart messages re-activating the progress screen right + // after tp, keep the teleport state and let progress screen clear it after a short delay + // (progress screen is active but not visible) *TODO: remove when SVC-5290 is fixed + gTeleportDisplayTimer.reset(); + gTeleportDisplay = TRUE; + } + else + { + LL_WARNS("Teleport") << "State is not TELEPORT_LOCAL: " << gAgent.getTeleportStateName() + << ", setting state to TELEPORT_NONE" << LL_ENDL; + gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + } + } + + // Sim tells us whether the new position is off the ground + if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) + { + gAgent.setFlying(TRUE); + } + else + { + gAgent.setFlying(FALSE); + } + + gAgent.setPositionAgent(pos); + gAgentCamera.slamLookAt(look_at); + + if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) ) + { + gAgentCamera.resetView(TRUE, TRUE); + } + + // send camera update to new region + gAgentCamera.updateCamera(); + + send_agent_update(TRUE, TRUE); + + // Let the interested parties know we've teleported. + // Vadim *HACK: Agent position seems to get reset (to render position?) + // on each frame, so we have to pass the new position manually. + LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos)); } void send_simple_im(const LLUUID& to_id, - const std::string& message, - EInstantMessage dialog, - const LLUUID& id) -{ - std::string my_name; - LLAgentUI::buildFullname(my_name); - send_improved_im(to_id, - my_name, - message, - IM_ONLINE, - dialog, - id, - NO_TIMESTAMP, - (U8*)EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); + const std::string& message, + EInstantMessage dialog, + const LLUUID& id) +{ + std::string my_name; + LLAgentUI::buildFullname(my_name); + send_improved_im(to_id, + my_name, + message, + IM_ONLINE, + dialog, + id, + NO_TIMESTAMP, + (U8*)EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); } void send_group_notice(const LLUUID& group_id, - const std::string& subject, - const std::string& message, - const LLInventoryItem* item) -{ - // Put this notice into an instant message form. - // This will mean converting the item to a binary bucket, - // and the subject/message into a single field. - std::string my_name; - LLAgentUI::buildFullname(my_name); - - // Combine subject + message into a single string. - std::ostringstream subject_and_message; - // TODO: turn all existing |'s into ||'s in subject and message. - subject_and_message << subject << "|" << message; - - // Create an empty binary bucket. - U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE]; - U8* bucket_to_send = bin_bucket; - bin_bucket[0] = '\0'; - S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE; - // If there is an item being sent, pack it into the binary bucket. - if (item) - { - LLSD item_def; - item_def["item_id"] = item->getUUID(); - item_def["owner_id"] = item->getPermissions().getOwner(); - std::ostringstream ostr; - LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML); - bin_bucket_size = ostr.str().copy( - (char*)bin_bucket, ostr.str().size()); - bin_bucket[bin_bucket_size] = '\0'; - } - else - { - bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; - } - - - send_improved_im( - group_id, - my_name, - subject_and_message.str(), - IM_ONLINE, - IM_GROUP_NOTICE, - LLUUID::null, - NO_TIMESTAMP, - bucket_to_send, - bin_bucket_size); + const std::string& subject, + const std::string& message, + const LLInventoryItem* item) +{ + // Put this notice into an instant message form. + // This will mean converting the item to a binary bucket, + // and the subject/message into a single field. + std::string my_name; + LLAgentUI::buildFullname(my_name); + + // Combine subject + message into a single string. + std::ostringstream subject_and_message; + // TODO: turn all existing |'s into ||'s in subject and message. + subject_and_message << subject << "|" << message; + + // Create an empty binary bucket. + U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE]; + U8* bucket_to_send = bin_bucket; + bin_bucket[0] = '\0'; + S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE; + // If there is an item being sent, pack it into the binary bucket. + if (item) + { + LLSD item_def; + item_def["item_id"] = item->getUUID(); + item_def["owner_id"] = item->getPermissions().getOwner(); + std::ostringstream ostr; + LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML); + bin_bucket_size = ostr.str().copy( + (char*)bin_bucket, ostr.str().size()); + bin_bucket[bin_bucket_size] = '\0'; + } + else + { + bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; + } + + + send_improved_im( + group_id, + my_name, + subject_and_message.str(), + IM_ONLINE, + IM_GROUP_NOTICE, + LLUUID::null, + NO_TIMESTAMP, + bucket_to_send, + 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. - { - LLAvatarName av_name; - LLAvatarNameCache::get(target_id, &av_name); // for im log filenames - LLSD args; - args["TO_NAME"] = LLSLURL("agent", target_id, "completename").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(); + 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. + { + LLAvatarName av_name; + LLAvatarNameCache::get(target_id, &av_name); // for im log filenames + LLSD args; + args["TO_NAME"] = LLSLURL("agent", target_id, "completename").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; - if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) - { - // More than OFFER_RECIPIENT_LIMIT targets will overload the message - // producing an llerror. - LLSD args; - args["OFFERS"] = LLSD::Integer(notification["payload"]["ids"].size()); - args["LIMIT"] = static_cast(OFFER_RECIPIENT_LIMIT); - LLNotificationsUtil::add("TooManyTeleportOffers", args); - return false; - } + static const unsigned OFFER_RECIPIENT_LIMIT = 250; + if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) + { + // More than OFFER_RECIPIENT_LIMIT targets will overload the message + // producing an llerror. + LLSD args; + args["OFFERS"] = LLSD::Integer(notification["payload"]["ids"].size()); + args["LIMIT"] = static_cast(OFFER_RECIPIENT_LIMIT); + LLNotificationsUtil::add("TooManyTeleportOffers", args); + return false; + } - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(0 == option) - { - send_lures(notification, response); - } + if(0 == option) + { + send_lures(notification, response); + } - return false; + return false; } void handle_lure(const LLUUID& invitee) { - std::vector ids; - ids.push_back(invitee); - handle_lure(ids); + std::vector ids; + ids.push_back(invitee); + handle_lure(ids); } // Prompt for a message to the invited user. void handle_lure(const uuid_vec_t& ids) { - if (ids.empty()) return; + if (ids.empty()) return; - if (!gAgent.getRegion()) return; + if (!gAgent.getRegion()) return; - LLSD edit_args; - edit_args["REGION"] = gAgent.getRegion()->getName(); + LLSD edit_args; + edit_args["REGION"] = gAgent.getRegion()->getName(); - LLSD payload; - for (std::vector::const_iterator it = ids.begin(); - it != ids.end(); - ++it) - { - payload["ids"].append(*it); - } - if (gAgent.isGodlike()) - { - LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); - } - else - { - LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback); - } + LLSD payload; + for (std::vector::const_iterator it = ids.begin(); + it != ids.end(); + ++it) + { + payload["ids"].append(*it); + } + if (gAgent.isGodlike()) + { + LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); + } + else + { + LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback); + } } bool teleport_request_callback(const LLSD& notification, const LLSD& response) { - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - if(from_id.isNull()) - { - LL_WARNS() << "from_id is NULL" << LL_ENDL; - return false; - } - - LLAvatarName av_name; - LLAvatarNameCache::get(from_id, &av_name); - - if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::isLinden(av_name.getUserName())) - { - 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; + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + if(from_id.isNull()) + { + LL_WARNS() << "from_id is NULL" << LL_ENDL; + return false; + } + + LLAvatarName av_name; + LLAvatarNameCache::get(from_id, &av_name); + + if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::isLinden(av_name.getUserName())) + { + 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, - const std::string& message, - U8 offline, - EInstantMessage dialog, - const LLUUID& id, - U32 timestamp, - const U8* binary_bucket, - S32 binary_bucket_size) -{ - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - to_id, - name, - message, - offline, - dialog, - id, - 0, - LLUUID::null, - gAgent.getPositionAgent(), - timestamp, - binary_bucket, - binary_bucket_size); - gAgent.sendReliableMessage(); + const std::string& name, + const std::string& message, + U8 offline, + EInstantMessage dialog, + const LLUUID& id, + U32 timestamp, + const U8* binary_bucket, + S32 binary_bucket_size) +{ + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + to_id, + name, + message, + offline, + dialog, + id, + 0, + LLUUID::null, + gAgent.getPositionAgent(), + timestamp, + binary_bucket, + binary_bucket_size); + gAgent.sendReliableMessage(); } void send_places_query(const LLUUID& query_id, - const LLUUID& trans_id, - const std::string& query_text, - U32 query_flags, - S32 category, - const std::string& sim_name) -{ - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage("PlacesQuery"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUID("QueryID", query_id); - msg->nextBlock("TransactionData"); - msg->addUUID("TransactionID", trans_id); - msg->nextBlock("QueryData"); - msg->addString("QueryText", query_text); - msg->addU32("QueryFlags", query_flags); - msg->addS8("Category", (S8)category); - msg->addString("SimName", sim_name); - gAgent.sendReliableMessage(); + const LLUUID& trans_id, + const std::string& query_text, + U32 query_flags, + S32 category, + const std::string& sim_name) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage("PlacesQuery"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUID("QueryID", query_id); + msg->nextBlock("TransactionData"); + msg->addUUID("TransactionID", trans_id); + msg->nextBlock("QueryData"); + msg->addString("QueryText", query_text); + msg->addU32("QueryFlags", query_flags); + msg->addS8("Category", (S8)category); + msg->addString("SimName", sim_name); + gAgent.sendReliableMessage(); } // Deprecated in favor of cap "UserInfo" void process_user_info_reply(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "process_user_info_reply - " - << "wrong agent id." << LL_ENDL; - } - - std::string email; - msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); - std::string dir_visibility; - msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS("Messaging") << "process_user_info_reply - " + << "wrong agent id." << LL_ENDL; + } - LLFloaterPreference::updateUserInfo(dir_visibility); - LLFloaterSnapshot::setAgentEmail(email); + std::string email; + msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); + std::string dir_visibility; + msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + + LLFloaterPreference::updateUserInfo(dir_visibility); + LLFloaterSnapshot::setAgentEmail(email); } @@ -6539,133 +6539,133 @@ const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n"; bool callback_script_dialog(const LLSD& notification, const LLSD& response) { - LLNotificationForm form(notification["form"]); - - std::string rtn_text; - S32 button_idx; - button_idx = LLNotification::getSelectedOption(notification, response); - if (response[TEXTBOX_MAGIC_TOKEN].isDefined()) - { - if (response[TEXTBOX_MAGIC_TOKEN].isString()) - rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString(); - else - rtn_text.clear(); // bool marks empty string - } - else - { - rtn_text = LLNotification::getSelectedOptionName(response); - } - - // Button -2 = Mute - // Button -1 = Ignore - no processing needed for this button - // Buttons 0 and above = dialog choices - - if (-2 == button_idx) - { - std::string object_name = notification["payload"]["object_name"].asString(); - LLUUID object_id = notification["payload"]["object_id"].asUUID(); - LLMute mute(object_id, object_name, LLMute::OBJECT); - if (LLMuteList::getInstance()->add(mute)) - { - // This call opens the sidebar, displays the block list, and highlights the newly blocked - // object in the list so the user can see that their block click has taken effect. - LLPanelBlockedList::showPanelAndSelect(object_id); - } - } - - if (0 <= button_idx) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("ScriptDialogReply"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); - msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); - msg->addS32("ButtonIndex", button_idx); - msg->addString("ButtonLabel", rtn_text); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - } - - return false; + LLNotificationForm form(notification["form"]); + + std::string rtn_text; + S32 button_idx; + button_idx = LLNotification::getSelectedOption(notification, response); + if (response[TEXTBOX_MAGIC_TOKEN].isDefined()) + { + if (response[TEXTBOX_MAGIC_TOKEN].isString()) + rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString(); + else + rtn_text.clear(); // bool marks empty string + } + else + { + rtn_text = LLNotification::getSelectedOptionName(response); + } + + // Button -2 = Mute + // Button -1 = Ignore - no processing needed for this button + // Buttons 0 and above = dialog choices + + if (-2 == button_idx) + { + std::string object_name = notification["payload"]["object_name"].asString(); + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLMute mute(object_id, object_name, LLMute::OBJECT); + if (LLMuteList::getInstance()->add(mute)) + { + // This call opens the sidebar, displays the block list, and highlights the newly blocked + // object in the list so the user can see that their block click has taken effect. + LLPanelBlockedList::showPanelAndSelect(object_id); + } + } + + if (0 <= button_idx) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("ScriptDialogReply"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); + msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); + msg->addS32("ButtonIndex", button_idx); + msg->addString("ButtonLabel", rtn_text); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + } + + return false; } static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); void process_script_dialog(LLMessageSystem* msg, void**) { - S32 i; - LLSD payload; + S32 i; + LLSD payload; - LLUUID object_id; - msg->getUUID("Data", "ObjectID", object_id); + LLUUID object_id; + msg->getUUID("Data", "ObjectID", object_id); -// For compability with OS grids first check for presence of extended packet before fetching data. +// For compability with OS grids first check for presence of extended packet before fetching data. LLUUID owner_id; - if (gMessageSystem->getNumberOfBlocks("OwnerData") > 0) - { + if (gMessageSystem->getNumberOfBlocks("OwnerData") > 0) + { msg->getUUID("OwnerData", "OwnerID", owner_id); - } - - if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id)) - { - return; - } - - std::string message; - std::string first_name; - std::string last_name; - std::string object_name; - - S32 chat_channel; - msg->getString("Data", "FirstName", first_name); - msg->getString("Data", "LastName", last_name); - msg->getString("Data", "ObjectName", object_name); - msg->getString("Data", "Message", message); - msg->getS32("Data", "ChatChannel", chat_channel); - - // unused for now - LLUUID image_id; - msg->getUUID("Data", "ImageID", image_id); - - payload["sender"] = msg->getSender().getIPandPort(); - payload["object_id"] = object_id; - payload["chat_channel"] = chat_channel; - payload["object_name"] = object_name; - - // build up custom form - S32 button_count = msg->getNumberOfBlocks("Buttons"); - if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) - { - LL_WARNS() << "Too many script dialog buttons - omitting some" << LL_ENDL; - button_count = SCRIPT_DIALOG_MAX_BUTTONS; - } - - LLNotificationForm form; - for (i = 0; i < button_count; i++) - { - std::string tdesc; - msg->getString("Buttons", "ButtonLabel", tdesc, i); - form.addElement("button", std::string(tdesc)); - } - - LLSD args; - args["TITLE"] = object_name; - args["MESSAGE"] = message; - LLNotificationPtr notification; - if (!first_name.empty()) - { - args["NAME"] = LLCacheName::buildFullName(first_name, last_name); - notification = LLNotifications::instance().add( - LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); - } - else - { - args["GROUPNAME"] = last_name; - notification = LLNotifications::instance().add( - LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD())); - } + } + + if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id)) + { + return; + } + + std::string message; + std::string first_name; + std::string last_name; + std::string object_name; + + S32 chat_channel; + msg->getString("Data", "FirstName", first_name); + msg->getString("Data", "LastName", last_name); + msg->getString("Data", "ObjectName", object_name); + msg->getString("Data", "Message", message); + msg->getS32("Data", "ChatChannel", chat_channel); + + // unused for now + LLUUID image_id; + msg->getUUID("Data", "ImageID", image_id); + + payload["sender"] = msg->getSender().getIPandPort(); + payload["object_id"] = object_id; + payload["chat_channel"] = chat_channel; + payload["object_name"] = object_name; + + // build up custom form + S32 button_count = msg->getNumberOfBlocks("Buttons"); + if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) + { + LL_WARNS() << "Too many script dialog buttons - omitting some" << LL_ENDL; + button_count = SCRIPT_DIALOG_MAX_BUTTONS; + } + + LLNotificationForm form; + for (i = 0; i < button_count; i++) + { + std::string tdesc; + msg->getString("Buttons", "ButtonLabel", tdesc, i); + form.addElement("button", std::string(tdesc)); + } + + LLSD args; + args["TITLE"] = object_name; + args["MESSAGE"] = message; + LLNotificationPtr notification; + if (!first_name.empty()) + { + args["NAME"] = LLCacheName::buildFullName(first_name, last_name); + notification = LLNotifications::instance().add( + LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); + } + else + { + args["GROUPNAME"] = last_name; + notification = LLNotifications::instance().add( + LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD())); + } } //--------------------------------------------------------------------------- @@ -6675,14 +6675,14 @@ std::vector gLoadUrlList; bool callback_load_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"].asString()); + } - return false; + return false; } static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); @@ -6690,42 +6690,42 @@ static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", ca // Display confirmation dialog. void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group) { - std::vector::iterator it; - for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) - { - LLSD load_url_info = *it; - if (load_url_info["owner_id"].asUUID() == id) - { - it = gLoadUrlList.erase(it); - - std::string owner_name; - if (is_group) - { - owner_name = full_name + LLTrans::getString("Group"); - } - else - { - owner_name = full_name; - } - - // For legacy name-only mutes. - if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name)) - { - continue; - } - LLSD args; - args["URL"] = load_url_info["url"].asString(); - args["MESSAGE"] = load_url_info["message"].asString();; - args["OBJECTNAME"] = load_url_info["object_name"].asString(); - args["NAME_SLURL"] = LLSLURL(is_group ? "group" : "agent", id, "about").getSLURLString(); - - LLNotificationsUtil::add("LoadWebPage", args, load_url_info); - } - else - { - ++it; - } - } + std::vector::iterator it; + for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) + { + LLSD load_url_info = *it; + if (load_url_info["owner_id"].asUUID() == id) + { + it = gLoadUrlList.erase(it); + + std::string owner_name; + if (is_group) + { + owner_name = full_name + LLTrans::getString("Group"); + } + else + { + owner_name = full_name; + } + + // For legacy name-only mutes. + if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name)) + { + continue; + } + LLSD args; + args["URL"] = load_url_info["url"].asString(); + args["MESSAGE"] = load_url_info["message"].asString();; + args["OBJECTNAME"] = load_url_info["object_name"].asString(); + args["NAME_SLURL"] = LLSLURL(is_group ? "group" : "agent", id, "about").getSLURLString(); + + LLNotificationsUtil::add("LoadWebPage", args, load_url_info); + } + else + { + ++it; + } + } } // We've got the name of the person who owns the object hurling the url. @@ -6736,296 +6736,296 @@ void callback_load_url_avatar_name(const LLUUID& id, const LLAvatarName& av_name void process_load_url(LLMessageSystem* msg, void**) { - LLUUID object_id; - LLUUID owner_id; - BOOL owner_is_group; - char object_name[256]; /* Flawfinder: ignore */ - char message[256]; /* Flawfinder: ignore */ - char url[256]; /* Flawfinder: ignore */ - - msg->getString("Data", "ObjectName", 256, object_name); - msg->getUUID( "Data", "ObjectID", object_id); - msg->getUUID( "Data", "OwnerID", owner_id); - msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); - msg->getString("Data", "Message", 256, message); - msg->getString("Data", "URL", 256, url); - - LLSD payload; - payload["object_id"] = object_id; - payload["owner_id"] = owner_id; - payload["owner_is_group"] = owner_is_group; - payload["object_name"] = object_name; - payload["message"] = message; - payload["url"] = url; - - // URL is safety checked in load_url above - - // Check if object or owner is muted - if (LLMuteList::getInstance()->isMuted(object_id, object_name) || - LLMuteList::getInstance()->isMuted(owner_id)) - { - LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<getGroup(owner_id, boost::bind(&callback_load_url_name, _1, _2, _3)); - } - else - { - LLAvatarNameCache::get(owner_id, boost::bind(&callback_load_url_avatar_name, _1, _2)); - } + LLUUID object_id; + LLUUID owner_id; + BOOL owner_is_group; + char object_name[256]; /* Flawfinder: ignore */ + char message[256]; /* Flawfinder: ignore */ + char url[256]; /* Flawfinder: ignore */ + + msg->getString("Data", "ObjectName", 256, object_name); + msg->getUUID( "Data", "ObjectID", object_id); + msg->getUUID( "Data", "OwnerID", owner_id); + msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); + msg->getString("Data", "Message", 256, message); + msg->getString("Data", "URL", 256, url); + + LLSD payload; + payload["object_id"] = object_id; + payload["owner_id"] = owner_id; + payload["owner_is_group"] = owner_is_group; + payload["object_name"] = object_name; + payload["message"] = message; + payload["url"] = url; + + // URL is safety checked in load_url above + + // Check if object or owner is muted + if (LLMuteList::getInstance()->isMuted(object_id, object_name) || + LLMuteList::getInstance()->isMuted(owner_id)) + { + LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<getGroup(owner_id, boost::bind(&callback_load_url_name, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(owner_id, boost::bind(&callback_load_url_avatar_name, _1, _2)); + } } void callback_download_complete(void** data, S32 result, LLExtStat ext_status) { - std::string* filepath = (std::string*)data; - LLSD args; - args["DOWNLOAD_PATH"] = *filepath; - LLNotificationsUtil::add("FinishedRawDownload", args); - delete filepath; + std::string* filepath = (std::string*)data; + LLSD args; + args["DOWNLOAD_PATH"] = *filepath; + LLNotificationsUtil::add("FinishedRawDownload", args); + delete filepath; } void process_initiate_download(LLMessageSystem* msg, void**) { - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL; - return; - } - - std::string sim_filename; - std::string viewer_filename; - msg->getString("FileData", "SimFilename", sim_filename); - msg->getString("FileData", "ViewerFilename", viewer_filename); - - if (!gXferManager->validateFileForRequest(viewer_filename)) - { - LL_WARNS() << "SECURITY: Unauthorized download to local file " << viewer_filename << LL_ENDL; - return; - } - gXferManager->requestFile(viewer_filename, - sim_filename, - LL_PATH_NONE, - msg->getSender(), - FALSE, // don't delete remote - callback_download_complete, - (void**)new std::string(viewer_filename)); + LLUUID agent_id; + msg->getUUID("AgentData", "AgentID", agent_id); + if (agent_id != gAgent.getID()) + { + LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL; + return; + } + + std::string sim_filename; + std::string viewer_filename; + msg->getString("FileData", "SimFilename", sim_filename); + msg->getString("FileData", "ViewerFilename", viewer_filename); + + if (!gXferManager->validateFileForRequest(viewer_filename)) + { + LL_WARNS() << "SECURITY: Unauthorized download to local file " << viewer_filename << LL_ENDL; + return; + } + gXferManager->requestFile(viewer_filename, + sim_filename, + LL_PATH_NONE, + msg->getSender(), + FALSE, // don't delete remote + callback_download_complete, + (void**)new std::string(viewer_filename)); } void process_script_teleport_request(LLMessageSystem* msg, void**) { - if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return; + if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return; + + std::string object_name; + std::string sim_name; + LLVector3 pos; + LLVector3 look_at; - std::string object_name; - std::string sim_name; - LLVector3 pos; - LLVector3 look_at; + msg->getString("Data", "ObjectName", object_name); + msg->getString("Data", "SimName", sim_name); + msg->getVector3("Data", "SimPosition", pos); + msg->getVector3("Data", "LookAt", look_at); - msg->getString("Data", "ObjectName", object_name); - msg->getString("Data", "SimName", sim_name); - msg->getVector3("Data", "SimPosition", pos); - msg->getVector3("Data", "LookAt", look_at); + LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); + if(instance) + { + LL_INFOS() << "Object named " << object_name + << " is offering TP to region " + << sim_name << " position " << pos + << LL_ENDL; + + instance->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); + LLFloaterReg::showInstance("world_map", "center"); + } - LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); - if(instance) - { - LL_INFOS() << "Object named " << object_name - << " is offering TP to region " - << sim_name << " position " << pos - << LL_ENDL; + // remove above two lines and replace with below line + // to re-enable parcel browser for llMapDestination() + // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); - instance->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); - LLFloaterReg::showInstance("world_map", "center"); - } - - // remove above two lines and replace with below line - // to re-enable parcel browser for llMapDestination() - // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); - } void process_covenant_reply(LLMessageSystem* msg, void**) { - LLUUID covenant_id, estate_owner_id; - std::string estate_name; - U32 covenant_timestamp; - msg->getUUID("Data", "CovenantID", covenant_id); - msg->getU32("Data", "CovenantTimestamp", covenant_timestamp); - msg->getString("Data", "EstateName", estate_name); - msg->getUUID("Data", "EstateOwnerID", estate_owner_id); - - LLPanelEstateCovenant::updateEstateName(estate_name); - LLPanelLandCovenant::updateEstateName(estate_name); - LLPanelEstateInfo::updateEstateName(estate_name); - LLFloaterBuyLand::updateEstateName(estate_name); - - std::string owner_name = - LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); - LLPanelEstateCovenant::updateEstateOwnerName(owner_name); - LLPanelLandCovenant::updateEstateOwnerName(owner_name); - LLPanelEstateInfo::updateEstateOwnerName(owner_name); - LLFloaterBuyLand::updateEstateOwnerName(owner_name); - - LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel("places", "panel_place_profile"); - if (panel) - { - panel->updateEstateName(estate_name); - panel->updateEstateOwnerName(owner_name); - } - - // standard message, not from system - std::string last_modified; - if (covenant_timestamp == 0) - { - last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text"); - } - else - { - last_modified = LLTrans::getString("covenant_last_modified")+"[" - +LLTrans::getString("LTimeWeek")+"] [" - +LLTrans::getString("LTimeMonth")+"] [" - +LLTrans::getString("LTimeDay")+"] [" - +LLTrans::getString("LTimeHour")+"]:[" - +LLTrans::getString("LTimeMin")+"]:[" - +LLTrans::getString("LTimeSec")+"] [" - +LLTrans::getString("LTimeYear")+"]"; - LLSD substitution; - substitution["datetime"] = (S32) covenant_timestamp; - LLStringUtil::format (last_modified, substitution); - } - - LLPanelEstateCovenant::updateLastModified(last_modified); - LLPanelLandCovenant::updateLastModified(last_modified); - LLFloaterBuyLand::updateLastModified(last_modified); - - // load the actual covenant asset data - const BOOL high_priority = TRUE; - if (covenant_id.notNull()) - { - gAssetStorage->getEstateAsset(gAgent.getRegionHost(), - gAgent.getID(), - gAgent.getSessionID(), - covenant_id, + LLUUID covenant_id, estate_owner_id; + std::string estate_name; + U32 covenant_timestamp; + msg->getUUID("Data", "CovenantID", covenant_id); + msg->getU32("Data", "CovenantTimestamp", covenant_timestamp); + msg->getString("Data", "EstateName", estate_name); + msg->getUUID("Data", "EstateOwnerID", estate_owner_id); + + LLPanelEstateCovenant::updateEstateName(estate_name); + LLPanelLandCovenant::updateEstateName(estate_name); + LLPanelEstateInfo::updateEstateName(estate_name); + LLFloaterBuyLand::updateEstateName(estate_name); + + std::string owner_name = + LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); + LLPanelEstateCovenant::updateEstateOwnerName(owner_name); + LLPanelLandCovenant::updateEstateOwnerName(owner_name); + LLPanelEstateInfo::updateEstateOwnerName(owner_name); + LLFloaterBuyLand::updateEstateOwnerName(owner_name); + + LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel("places", "panel_place_profile"); + if (panel) + { + panel->updateEstateName(estate_name); + panel->updateEstateOwnerName(owner_name); + } + + // standard message, not from system + std::string last_modified; + if (covenant_timestamp == 0) + { + last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text"); + } + else + { + last_modified = LLTrans::getString("covenant_last_modified")+"[" + +LLTrans::getString("LTimeWeek")+"] [" + +LLTrans::getString("LTimeMonth")+"] [" + +LLTrans::getString("LTimeDay")+"] [" + +LLTrans::getString("LTimeHour")+"]:[" + +LLTrans::getString("LTimeMin")+"]:[" + +LLTrans::getString("LTimeSec")+"] [" + +LLTrans::getString("LTimeYear")+"]"; + LLSD substitution; + substitution["datetime"] = (S32) covenant_timestamp; + LLStringUtil::format (last_modified, substitution); + } + + LLPanelEstateCovenant::updateLastModified(last_modified); + LLPanelLandCovenant::updateLastModified(last_modified); + LLFloaterBuyLand::updateLastModified(last_modified); + + // load the actual covenant asset data + const BOOL high_priority = TRUE; + if (covenant_id.notNull()) + { + gAssetStorage->getEstateAsset(gAgent.getRegionHost(), + gAgent.getID(), + gAgent.getSessionID(), + covenant_id, LLAssetType::AT_NOTECARD, - ET_Covenant, + ET_Covenant, onCovenantLoadComplete, - NULL, - high_priority); - } - else - { - std::string covenant_text; - if (estate_owner_id.isNull()) - { - // mainland - covenant_text = LLTrans::getString("RegionNoCovenant"); - } - else - { - covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner"); - } - LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id); - if (panel) - { - panel->updateCovenantText(covenant_text); - } - } + NULL, + high_priority); + } + else + { + std::string covenant_text; + if (estate_owner_id.isNull()) + { + // mainland + covenant_text = LLTrans::getString("RegionNoCovenant"); + } + else + { + covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner"); + } + LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); + LLPanelLandCovenant::updateCovenantText(covenant_text); + LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id); + if (panel) + { + panel->updateCovenantText(covenant_text); + } + } } void onCovenantLoadComplete(const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) -{ - LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; - std::string covenant_text; - if(0 == status) - { - LLFileSystem file(asset_uuid, type, LLFileSystem::READ); - - S32 file_length = file.getSize(); - - std::vector buffer(file_length+1); - file.read((U8*)&buffer[0], file_length); - // put a EOS at the end - buffer[file_length] = '\0'; - - if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) - { - LLViewerTextEditor::Params params; - params.name("temp"); - params.max_text_length(file_length+1); - LLViewerTextEditor * editor = LLUICtrlFactory::create (params); - if( !editor->importBuffer( &buffer[0], file_length+1 ) ) - { - LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; - covenant_text = "Problem importing estate covenant."; - } - else - { - // Version 0 (just text, doesn't include version number) - covenant_text = editor->getText(); - } - delete editor; - } - else - { - LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL; - covenant_text = "Problem importing estate covenant: Covenant file format error."; - } - } - else - { - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || - LL_ERR_FILE_EMPTY == status) - { - covenant_text = "Estate covenant notecard is missing from database."; - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) - { - covenant_text = "Insufficient permissions to view estate covenant."; - } - else - { - covenant_text = "Unable to load estate covenant at this time."; - } - - LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL; - } - LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); - - LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel("places", "panel_place_profile"); - if (panel) - { - panel->updateCovenantText(covenant_text); - } + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; + std::string covenant_text; + if(0 == status) + { + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); + + S32 file_length = file.getSize(); + + std::vector buffer(file_length+1); + file.read((U8*)&buffer[0], file_length); + // put a EOS at the end + buffer[file_length] = '\0'; + + if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) + { + LLViewerTextEditor::Params params; + params.name("temp"); + params.max_text_length(file_length+1); + LLViewerTextEditor * editor = LLUICtrlFactory::create (params); + if( !editor->importBuffer( &buffer[0], file_length+1 ) ) + { + LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; + covenant_text = "Problem importing estate covenant."; + } + else + { + // Version 0 (just text, doesn't include version number) + covenant_text = editor->getText(); + } + delete editor; + } + else + { + LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL; + covenant_text = "Problem importing estate covenant: Covenant file format error."; + } + } + else + { + if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + covenant_text = "Estate covenant notecard is missing from database."; + } + else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + { + covenant_text = "Insufficient permissions to view estate covenant."; + } + else + { + covenant_text = "Unable to load estate covenant at this time."; + } + + LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL; + } + LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); + LLPanelLandCovenant::updateCovenantText(covenant_text); + LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); + + LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel("places", "panel_place_profile"); + if (panel) + { + panel->updateCovenantText(covenant_text); + } } void process_feature_disabled_message(LLMessageSystem* msg, void**) { - // Handle Blacklisted feature simulator response... - LLUUID agentID; - LLUUID transactionID; - std::string messageText; - msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); - - LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; + // Handle Blacklisted feature simulator response... + LLUUID agentID; + LLUUID transactionID; + std::string messageText; + msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); + msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); + msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); + + LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; } // ------------------------------------------------------------ @@ -7033,8 +7033,8 @@ void process_feature_disabled_message(LLMessageSystem* msg, void**) // ------------------------------------------------------------ void invalid_message_callback(LLMessageSystem* msg, - void*, - EMessageException exception) + void*, + EMessageException exception) { LLAppViewer::instance()->badNetworkHandler(); } @@ -7044,8 +7044,8 @@ void invalid_message_callback(LLMessageSystem* msg, void LLOfferInfo::forceResponse(InventoryOfferResponse response) { - LLNotification::Params params("UserGiveItem"); - params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); - LLNotifications::instance().forceResponse(params, response); + LLNotification::Params params("UserGiveItem"); + params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); + LLNotifications::instance().forceResponse(params, response); } diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index 8cf86910e7..d9575e0b2b 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2007&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$ */ @@ -46,11 +46,11 @@ const F32 AUTOPLAY_SIZE = 24*24; // how big the texture must be (pixel are const F32 AUTOPLAY_SPEED = 0.1f; // how slow should the agent be moving to autoplay LLViewerParcelMediaAutoPlay::LLViewerParcelMediaAutoPlay() : - LLEventTimer(1), - - mLastParcelID(-1), - mPlayed(FALSE), - mTimeInParcel(0) + LLEventTimer(1), + + mLastParcelID(-1), + mPlayed(FALSE), + mTimeInParcel(0) { } @@ -62,101 +62,101 @@ void LLViewerParcelMediaAutoPlay::playStarted() bool LLViewerParcelMediaAutoPlay::tick() { - LLParcel *this_parcel = NULL; - LLViewerRegion *this_region = NULL; - std::string this_media_url; - std::string this_media_type; - LLUUID this_media_texture_id; - S32 this_parcel_id = 0; - LLUUID this_region_id; - - this_region = gAgent.getRegion(); - - if (this_region) - { - this_region_id = this_region->getRegionID(); - } - - this_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - - if (this_parcel) - { - this_media_url = this_parcel->getMediaURL(); - - this_media_type = this_parcel->getMediaType(); - - this_media_texture_id = this_parcel->getMediaID(); - - this_parcel_id = this_parcel->getLocalID(); - } - - if (this_parcel_id != mLastParcelID || - this_region_id != mLastRegionID) - { - // we've entered a new parcel - mPlayed = FALSE; // we haven't autoplayed yet - mTimeInParcel = 0; // reset our timer - mLastParcelID = this_parcel_id; - mLastRegionID = this_region_id; - } - - mTimeInParcel += mPeriod; // increase mTimeInParcel by the amount of time between ticks - - if ((!mPlayed) && // if we've never played - (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds - (!this_media_url.empty()) && // and if the parcel has media - (stricmp(this_media_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) && - (!LLViewerParcelMedia::getInstance()->hasParcelMedia())) // and if the media is not already playing - { - if (this_media_texture_id.notNull()) // and if the media texture is good - { - LLViewerMediaTexture *image = LLViewerTextureManager::getMediaTexture(this_media_texture_id, FALSE) ; - - F32 image_size = 0; - - if (image) - { - image_size = image->getMaxVirtualSize() ; - } - - if (gAgent.getVelocity().magVec() < AUTOPLAY_SPEED) // and if the agent is stopped (slow enough) - { - if (image_size > AUTOPLAY_SIZE) // and if the target texture is big enough on screen - { - if (this_parcel) - { - static LLCachedControl autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); - - switch (autoplay_mode()) - { - case 0: - // Disabled - break; - case 1: - // Play, default value for ParcelMediaAutoPlayEnable - LLViewerParcelMedia::getInstance()->play(this_parcel); - break; - case 2: - default: - { - // Ask - LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), - this_parcel->getLocalID(), - this_parcel->getMediaURL(), - onStartMediaResponse); - break; - } - } - } - - mPlayed = TRUE; - } - } - } - } - - - return false; // continue ticking forever please. + LLParcel *this_parcel = NULL; + LLViewerRegion *this_region = NULL; + std::string this_media_url; + std::string this_media_type; + LLUUID this_media_texture_id; + S32 this_parcel_id = 0; + LLUUID this_region_id; + + this_region = gAgent.getRegion(); + + if (this_region) + { + this_region_id = this_region->getRegionID(); + } + + this_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + if (this_parcel) + { + this_media_url = this_parcel->getMediaURL(); + + this_media_type = this_parcel->getMediaType(); + + this_media_texture_id = this_parcel->getMediaID(); + + this_parcel_id = this_parcel->getLocalID(); + } + + if (this_parcel_id != mLastParcelID || + this_region_id != mLastRegionID) + { + // we've entered a new parcel + mPlayed = FALSE; // we haven't autoplayed yet + mTimeInParcel = 0; // reset our timer + mLastParcelID = this_parcel_id; + mLastRegionID = this_region_id; + } + + mTimeInParcel += mPeriod; // increase mTimeInParcel by the amount of time between ticks + + if ((!mPlayed) && // if we've never played + (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds + (!this_media_url.empty()) && // and if the parcel has media + (stricmp(this_media_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) && + (!LLViewerParcelMedia::getInstance()->hasParcelMedia())) // and if the media is not already playing + { + if (this_media_texture_id.notNull()) // and if the media texture is good + { + LLViewerMediaTexture *image = LLViewerTextureManager::getMediaTexture(this_media_texture_id, FALSE) ; + + F32 image_size = 0; + + if (image) + { + image_size = image->getMaxVirtualSize() ; + } + + if (gAgent.getVelocity().magVec() < AUTOPLAY_SPEED) // and if the agent is stopped (slow enough) + { + if (image_size > AUTOPLAY_SIZE) // and if the target texture is big enough on screen + { + if (this_parcel) + { + static LLCachedControl autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); + + switch (autoplay_mode()) + { + case 0: + // Disabled + break; + case 1: + // Play, default value for ParcelMediaAutoPlayEnable + LLViewerParcelMedia::getInstance()->play(this_parcel); + break; + case 2: + default: + { + // Ask + LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), + this_parcel->getLocalID(), + this_parcel->getMediaURL(), + onStartMediaResponse); + break; + } + } + } + + mPlayed = TRUE; + } + } + } + } + + + return false; // continue ticking forever please. } //static diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index 9367c2a629..506fb38901 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2007&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$ */ @@ -33,20 +33,20 @@ // timer to automatically play media class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton { - LLSINGLETON(LLViewerParcelMediaAutoPlay); + LLSINGLETON(LLViewerParcelMediaAutoPlay); public: - bool tick() override; - static void playStarted(); + bool tick() override; + static void playStarted(); private: // for askToPlay - static void onStartMediaResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + static void onStartMediaResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); private: - S32 mLastParcelID; - LLUUID mLastRegionID; - BOOL mPlayed; - F32 mTimeInParcel; + S32 mLastParcelID; + LLUUID mLastRegionID; + BOOL mPlayed; + F32 mTimeInParcel; }; diff --git a/indra/test/io.cpp b/indra/test/io.cpp index 88c22e7508..5bc169fd78 100644 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -1,4 +1,4 @@ -/** +/** * @file io.cpp * @author Phoenix * @date 2005-10-02 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&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$ */ @@ -49,1153 +49,1153 @@ namespace tut { - struct heap_buffer_data - { - heap_buffer_data() : mBuffer(NULL) {} - ~heap_buffer_data() { if(mBuffer) delete mBuffer; } - LLHeapBuffer* mBuffer; - }; - typedef test_group heap_buffer_test; - typedef heap_buffer_test::object heap_buffer_object; - tut::heap_buffer_test thb("heap_buffer"); - - template<> template<> - void heap_buffer_object::test<1>() - { - const S32 BUF_SIZE = 100; - mBuffer = new LLHeapBuffer(BUF_SIZE); - ensure_equals("empty buffer capacity", mBuffer->capacity(), BUF_SIZE); - const S32 SEGMENT_SIZE = 50; - LLSegment segment; - mBuffer->createSegment(0, SEGMENT_SIZE, segment); - ensure_equals("used buffer capacity", mBuffer->capacity(), BUF_SIZE); - } - - template<> template<> - void heap_buffer_object::test<2>() - { - const S32 BUF_SIZE = 10; - mBuffer = new LLHeapBuffer(BUF_SIZE); - LLSegment segment; - mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("segment is in buffer", mBuffer->containsSegment(segment)); - ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); - bool created; - created = mBuffer->createSegment(0, 0, segment); - ensure("Create zero size segment fails", !created); - created = mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("Create segment fails", !created); - } - - template<> template<> - void heap_buffer_object::test<3>() - { - const S32 BUF_SIZE = 10; - mBuffer = new LLHeapBuffer(BUF_SIZE); - LLSegment segment; - mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("segment is in buffer", mBuffer->containsSegment(segment)); - ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); - bool reclaimed = mBuffer->reclaimSegment(segment); - ensure("buffer reclaimed.", reclaimed); - ensure_equals("buffer available", mBuffer->bytesLeft(), BUF_SIZE); - bool created; - created = mBuffer->createSegment(0, 0, segment); - ensure("Create zero size segment fails", !created); - created = mBuffer->createSegment(0, BUF_SIZE, segment); - ensure("Create another segment succeeds", created); - } - - template<> template<> - void heap_buffer_object::test<4>() - { - const S32 BUF_SIZE = 10; - const S32 SEGMENT_SIZE = 4; - mBuffer = new LLHeapBuffer(BUF_SIZE); - LLSegment seg1; - mBuffer->createSegment(0, SEGMENT_SIZE, seg1); - ensure("segment is in buffer", mBuffer->containsSegment(seg1)); - LLSegment seg2; - mBuffer->createSegment(0, SEGMENT_SIZE, seg2); - ensure("segment is in buffer", mBuffer->containsSegment(seg2)); - LLSegment seg3; - mBuffer->createSegment(0, SEGMENT_SIZE, seg3); - ensure("segment is in buffer", mBuffer->containsSegment(seg3)); - ensure_equals("segment is truncated", seg3.size(), 2); - LLSegment seg4; - bool created; - created = mBuffer->createSegment(0, SEGMENT_SIZE, seg4); - ensure("Create segment fails", !created); - bool reclaimed; - reclaimed = mBuffer->reclaimSegment(seg1); - ensure("buffer reclaim succeed.", reclaimed); - ensure_equals("no buffer available", mBuffer->bytesLeft(), 0); - reclaimed = mBuffer->reclaimSegment(seg2); - ensure("buffer reclaim succeed.", reclaimed); - ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), 0); - reclaimed = mBuffer->reclaimSegment(seg3); - ensure("buffer reclaim succeed.", reclaimed); - ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), BUF_SIZE); - created = mBuffer->createSegment(0, SEGMENT_SIZE, seg1); - ensure("segment is in buffer", mBuffer->containsSegment(seg1)); - ensure("Create segment succeds", created); - } + struct heap_buffer_data + { + heap_buffer_data() : mBuffer(NULL) {} + ~heap_buffer_data() { if(mBuffer) delete mBuffer; } + LLHeapBuffer* mBuffer; + }; + typedef test_group heap_buffer_test; + typedef heap_buffer_test::object heap_buffer_object; + tut::heap_buffer_test thb("heap_buffer"); + + template<> template<> + void heap_buffer_object::test<1>() + { + const S32 BUF_SIZE = 100; + mBuffer = new LLHeapBuffer(BUF_SIZE); + ensure_equals("empty buffer capacity", mBuffer->capacity(), BUF_SIZE); + const S32 SEGMENT_SIZE = 50; + LLSegment segment; + mBuffer->createSegment(0, SEGMENT_SIZE, segment); + ensure_equals("used buffer capacity", mBuffer->capacity(), BUF_SIZE); + } + + template<> template<> + void heap_buffer_object::test<2>() + { + const S32 BUF_SIZE = 10; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment segment; + mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("segment is in buffer", mBuffer->containsSegment(segment)); + ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); + bool created; + created = mBuffer->createSegment(0, 0, segment); + ensure("Create zero size segment fails", !created); + created = mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("Create segment fails", !created); + } + + template<> template<> + void heap_buffer_object::test<3>() + { + const S32 BUF_SIZE = 10; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment segment; + mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("segment is in buffer", mBuffer->containsSegment(segment)); + ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0); + bool reclaimed = mBuffer->reclaimSegment(segment); + ensure("buffer reclaimed.", reclaimed); + ensure_equals("buffer available", mBuffer->bytesLeft(), BUF_SIZE); + bool created; + created = mBuffer->createSegment(0, 0, segment); + ensure("Create zero size segment fails", !created); + created = mBuffer->createSegment(0, BUF_SIZE, segment); + ensure("Create another segment succeeds", created); + } + + template<> template<> + void heap_buffer_object::test<4>() + { + const S32 BUF_SIZE = 10; + const S32 SEGMENT_SIZE = 4; + mBuffer = new LLHeapBuffer(BUF_SIZE); + LLSegment seg1; + mBuffer->createSegment(0, SEGMENT_SIZE, seg1); + ensure("segment is in buffer", mBuffer->containsSegment(seg1)); + LLSegment seg2; + mBuffer->createSegment(0, SEGMENT_SIZE, seg2); + ensure("segment is in buffer", mBuffer->containsSegment(seg2)); + LLSegment seg3; + mBuffer->createSegment(0, SEGMENT_SIZE, seg3); + ensure("segment is in buffer", mBuffer->containsSegment(seg3)); + ensure_equals("segment is truncated", seg3.size(), 2); + LLSegment seg4; + bool created; + created = mBuffer->createSegment(0, SEGMENT_SIZE, seg4); + ensure("Create segment fails", !created); + bool reclaimed; + reclaimed = mBuffer->reclaimSegment(seg1); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("no buffer available", mBuffer->bytesLeft(), 0); + reclaimed = mBuffer->reclaimSegment(seg2); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), 0); + reclaimed = mBuffer->reclaimSegment(seg3); + ensure("buffer reclaim succeed.", reclaimed); + ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), BUF_SIZE); + created = mBuffer->createSegment(0, SEGMENT_SIZE, seg1); + ensure("segment is in buffer", mBuffer->containsSegment(seg1)); + ensure("Create segment succeds", created); + } } namespace tut { - struct buffer_data - { - LLBufferArray mBuffer; - }; - typedef test_group buffer_test; - typedef buffer_test::object buffer_object; - tut::buffer_test tba("buffer_array"); - - template<> template<> - void buffer_object::test<1>() - { - const char HELLO_WORLD[] = "hello world"; - const S32 str_len = strlen(HELLO_WORLD); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("total append size", count, str_len); - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - U8* first = (*it).data(); - count = mBuffer.countAfter(ch.in(), first); - ensure_equals("offset append size", count, str_len - 1); - } - - template<> template<> - void buffer_object::test<2>() - { - const char HELLO_WORLD[] = "hello world"; - const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("total append size", count, 2 * str_len); - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - U8* first = (*it).data(); - count = mBuffer.countAfter(ch.in(), first); - ensure_equals("offset append size", count, (2 * str_len) - 1); - } - - template<> template<> - void buffer_object::test<3>() - { - const char ONE[] = "one"; - const char TWO[] = "two"; - std::string expected(ONE); - expected.append(TWO); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)ONE, 3); - mBuffer.append(ch.in(), (U8*)TWO, 3); - char buffer[255]; /* Flawfinder: ignore */ - S32 len = 6; - mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); - ensure_equals(len, 6); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("read", actual, expected); - } - - template<> template<> - void buffer_object::test<4>() - { - const char ONE[] = "one"; - const char TWO[] = "two"; - std::string expected(ONE); - expected.append(TWO); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)TWO, 3); - mBuffer.prepend(ch.in(), (U8*)ONE, 3); - char buffer[255]; /* Flawfinder: ignore */ - S32 len = 6; - mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); - ensure_equals(len, 6); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("read", actual, expected); - } - - template<> template<> - void buffer_object::test<5>() - { - const char ONE[] = "one"; - const char TWO[] = "two"; - std::string expected("netwo"); - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)TWO, 3); - mBuffer.prepend(ch.in(), (U8*)ONE, 3); - char buffer[255]; /* Flawfinder: ignore */ - S32 len = 5; - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - U8* addr = (*it).data(); - mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len); - ensure_equals(len, 5); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("read", actual, expected); - } - - template<> template<> - void buffer_object::test<6>() - { - std::string request("The early bird catches the worm."); - std::string response("If you're a worm, sleep late."); - std::ostringstream expected; - expected << "ContentLength: " << response.length() << "\r\n\r\n" - << response; - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)request.c_str(), request.length()); - mBuffer.append(ch.out(), (U8*)response.c_str(), response.length()); - S32 count = mBuffer.countAfter(ch.out(), NULL); - std::ostringstream header; - header << "ContentLength: " << count << "\r\n\r\n"; - std::string head(header.str()); - mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length()); - char buffer[1024]; /* Flawfinder: ignore */ - S32 len = response.size() + head.length(); - ensure_equals("same length", len, (S32)expected.str().length()); - mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len); - buffer[len] = '\0'; - std::string actual(buffer); - ensure_equals("threaded writes", actual, expected.str()); - } - - template<> template<> - void buffer_object::test<7>() - { - const S32 LINE_COUNT = 3; - std::string lines[LINE_COUNT] = - { - std::string("GET /index.htm HTTP/1.0\r\n"), - std::string("User-Agent: Wget/1.9.1\r\n"), - std::string("Host: localhost:8008\r\n") - }; - std::string text; - S32 i; - for(i = 0; i < LINE_COUNT; ++i) - { - text.append(lines[i]); - } - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)text.c_str(), text.length()); - const S32 BUFFER_LEN = 1024; - char buf[BUFFER_LEN]; - S32 len; - U8* last = NULL; - std::string last_line; - for(i = 0; i < LINE_COUNT; ++i) - { - len = BUFFER_LEN; - last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len); - char* newline = strchr((char*)buf, '\n'); - S32 offset = -((len - 1) - (newline - buf)); - ++newline; - *newline = '\0'; - last_line.assign(buf); - std::ostringstream message; - message << "line reads in line[" << i << "]"; - ensure_equals(message.str().c_str(), last_line, lines[i]); - last = mBuffer.seek(ch.in(), last, offset); - } - } - - template<> template<> - void buffer_object::test<8>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)"1", 1); - LLBufferArray buffer; - buffer.append(ch.in(), (U8*)"2", 1); - mBuffer.takeContents(buffer); - mBuffer.append(ch.in(), (U8*)"3", 1); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("buffer size", count, 3); - U8* temp = new U8[count]; - mBuffer.readAfter(ch.in(), NULL, temp, count); - ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); - delete[] temp; - } - - template<> template<> - void buffer_object::test<9>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.in(), (U8*)"1", 1); - S32 capacity = mBuffer.capacity(); - ensure("has capacity", capacity > 0); - U8* temp = new U8[capacity - 1]; - mBuffer.append(ch.in(), temp, capacity - 1); - capacity = mBuffer.capacity(); - ensure("has capacity when full", capacity > 0); - S32 used = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("used equals capacity", used, capacity); - - LLBufferArray::segment_iterator_t iter = mBuffer.beginSegment(); - while(iter != mBuffer.endSegment()) - { - mBuffer.eraseSegment(iter++); - } - - used = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("used is zero", used, 0); - S32 capacity2 = mBuffer.capacity(); - ensure_equals("capacity the same after erase", capacity2, capacity); - mBuffer.append(ch.in(), temp, capacity - 1); - capacity2 = mBuffer.capacity(); - ensure_equals("capacity the same after append", capacity2, capacity); - - delete[] temp; - } + struct buffer_data + { + LLBufferArray mBuffer; + }; + typedef test_group buffer_test; + typedef buffer_test::object buffer_object; + tut::buffer_test tba("buffer_array"); + + template<> template<> + void buffer_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = strlen(HELLO_WORLD); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("total append size", count, str_len); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* first = (*it).data(); + count = mBuffer.countAfter(ch.in(), first); + ensure_equals("offset append size", count, str_len - 1); + } + + template<> template<> + void buffer_object::test<2>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("total append size", count, 2 * str_len); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* first = (*it).data(); + count = mBuffer.countAfter(ch.in(), first); + ensure_equals("offset append size", count, (2 * str_len) - 1); + } + + template<> template<> + void buffer_object::test<3>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected(ONE); + expected.append(TWO); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)ONE, 3); + mBuffer.append(ch.in(), (U8*)TWO, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 6; + mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); + ensure_equals(len, 6); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<4>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected(ONE); + expected.append(TWO); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)TWO, 3); + mBuffer.prepend(ch.in(), (U8*)ONE, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 6; + mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); + ensure_equals(len, 6); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<5>() + { + const char ONE[] = "one"; + const char TWO[] = "two"; + std::string expected("netwo"); + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)TWO, 3); + mBuffer.prepend(ch.in(), (U8*)ONE, 3); + char buffer[255]; /* Flawfinder: ignore */ + S32 len = 5; + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + U8* addr = (*it).data(); + mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len); + ensure_equals(len, 5); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("read", actual, expected); + } + + template<> template<> + void buffer_object::test<6>() + { + std::string request("The early bird catches the worm."); + std::string response("If you're a worm, sleep late."); + std::ostringstream expected; + expected << "ContentLength: " << response.length() << "\r\n\r\n" + << response; + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)request.c_str(), request.length()); + mBuffer.append(ch.out(), (U8*)response.c_str(), response.length()); + S32 count = mBuffer.countAfter(ch.out(), NULL); + std::ostringstream header; + header << "ContentLength: " << count << "\r\n\r\n"; + std::string head(header.str()); + mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length()); + char buffer[1024]; /* Flawfinder: ignore */ + S32 len = response.size() + head.length(); + ensure_equals("same length", len, (S32)expected.str().length()); + mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len); + buffer[len] = '\0'; + std::string actual(buffer); + ensure_equals("threaded writes", actual, expected.str()); + } + + template<> template<> + void buffer_object::test<7>() + { + const S32 LINE_COUNT = 3; + std::string lines[LINE_COUNT] = + { + std::string("GET /index.htm HTTP/1.0\r\n"), + std::string("User-Agent: Wget/1.9.1\r\n"), + std::string("Host: localhost:8008\r\n") + }; + std::string text; + S32 i; + for(i = 0; i < LINE_COUNT; ++i) + { + text.append(lines[i]); + } + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)text.c_str(), text.length()); + const S32 BUFFER_LEN = 1024; + char buf[BUFFER_LEN]; + S32 len; + U8* last = NULL; + std::string last_line; + for(i = 0; i < LINE_COUNT; ++i) + { + len = BUFFER_LEN; + last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len); + char* newline = strchr((char*)buf, '\n'); + S32 offset = -((len - 1) - (newline - buf)); + ++newline; + *newline = '\0'; + last_line.assign(buf); + std::ostringstream message; + message << "line reads in line[" << i << "]"; + ensure_equals(message.str().c_str(), last_line, lines[i]); + last = mBuffer.seek(ch.in(), last, offset); + } + } + + template<> template<> + void buffer_object::test<8>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)"1", 1); + LLBufferArray buffer; + buffer.append(ch.in(), (U8*)"2", 1); + mBuffer.takeContents(buffer); + mBuffer.append(ch.in(), (U8*)"3", 1); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("buffer size", count, 3); + U8* temp = new U8[count]; + mBuffer.readAfter(ch.in(), NULL, temp, count); + ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); + delete[] temp; + } + + template<> template<> + void buffer_object::test<9>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.in(), (U8*)"1", 1); + S32 capacity = mBuffer.capacity(); + ensure("has capacity", capacity > 0); + U8* temp = new U8[capacity - 1]; + mBuffer.append(ch.in(), temp, capacity - 1); + capacity = mBuffer.capacity(); + ensure("has capacity when full", capacity > 0); + S32 used = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("used equals capacity", used, capacity); + + LLBufferArray::segment_iterator_t iter = mBuffer.beginSegment(); + while(iter != mBuffer.endSegment()) + { + mBuffer.eraseSegment(iter++); + } + + used = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("used is zero", used, 0); + S32 capacity2 = mBuffer.capacity(); + ensure_equals("capacity the same after erase", capacity2, capacity); + mBuffer.append(ch.in(), temp, capacity - 1); + capacity2 = mBuffer.capacity(); + ensure_equals("capacity the same after append", capacity2, capacity); + + delete[] temp; + } #if 0 - template<> template<> - void buffer_object::test<9>() - { - char buffer[1024]; /* Flawfinder: ignore */ - S32 size = sprintf(buffer, - "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", - 7, - 7, - "Hang Glider INFO", - "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a", - "0e346d8b-4433-4d66-a6b0-fd37083abc4c", - "0e346d8b-4433-4d66-a6b0-fd37083abc4c", - "00000000-0000-0000-0000-000000000000", - 0x7fffffff, - 0x7fffffff, - 0, - 0, - 0x7fffffff, - "69e0d357-2e7c-8990-a2bc-7f61c868e5a3", - "2004-06-04 16:09:17 note card", - 0, - 10, - 0) + 1; - - //const char* expected = "7|7|Hang Glider INFO|18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a|0e346d8b-4433-4d66-a6b0-fd37083abc4c|0e346d8b-4433-4d66-a6b0-fd37083abc4c|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|7fffffff|69e0d357-2e7c-8990-a2bc-7f61c868e5a3|2004-06-04 16:09:17 note card|0|10|0\0"; - - LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size); - - char post_buffer[1024]; - U32 post_size; - LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size); - ensure_equals("Buffer sizes",size,(S32)post_size); - ensure("Buffer content",!strcmp(buffer,post_buffer)); - } + template<> template<> + void buffer_object::test<9>() + { + char buffer[1024]; /* Flawfinder: ignore */ + S32 size = sprintf(buffer, + "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", + 7, + 7, + "Hang Glider INFO", + "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a", + "0e346d8b-4433-4d66-a6b0-fd37083abc4c", + "0e346d8b-4433-4d66-a6b0-fd37083abc4c", + "00000000-0000-0000-0000-000000000000", + 0x7fffffff, + 0x7fffffff, + 0, + 0, + 0x7fffffff, + "69e0d357-2e7c-8990-a2bc-7f61c868e5a3", + "2004-06-04 16:09:17 note card", + 0, + 10, + 0) + 1; + + //const char* expected = "7|7|Hang Glider INFO|18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a|0e346d8b-4433-4d66-a6b0-fd37083abc4c|0e346d8b-4433-4d66-a6b0-fd37083abc4c|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|7fffffff|69e0d357-2e7c-8990-a2bc-7f61c868e5a3|2004-06-04 16:09:17 note card|0|10|0\0"; + + LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size); + + char post_buffer[1024]; + U32 post_size; + LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size); + ensure_equals("Buffer sizes",size,(S32)post_size); + ensure("Buffer content",!strcmp(buffer,post_buffer)); + } #endif - /* - template<> template<> - void buffer_object::test<>() - { - } - */ + /* + template<> template<> + void buffer_object::test<>() + { + } + */ } namespace tut { - struct buffer_and_stream_data - { - LLBufferArray mBuffer; - }; - typedef test_group bas_test; - typedef bas_test::object bas_object; - tut::bas_test tbs("buffer_stream"); - - template<> template<> - void bas_object::test<1>() - { - const char HELLO_WORLD[] = "hello world"; - const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream str(ch, &mBuffer); - mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); - std::string hello; - std::string world; - str >> hello >> world; - ensure_equals("first word", hello, std::string("hello")); - ensure_equals("second word", world, std::string("world")); - } - - template<> template<> - void bas_object::test<2>() - { - std::string part1("Eat my shor"); - std::string part2("ts ho"); - std::string part3("mer"); - std::string ignore("ignore me"); - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream str(ch, &mBuffer); - mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length()); - mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length()); - mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length()); - mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length()); - std::string eat; - std::string my; - std::string shorts; - std::string homer; - str >> eat >> my >> shorts >> homer; - ensure_equals("word1", eat, std::string("Eat")); - ensure_equals("word2", my, std::string("my")); - ensure_equals("word3", shorts, std::string("shorts")); - ensure_equals("word4", homer, std::string("homer")); - } - - template<> template<> - void bas_object::test<3>() - { - std::string part1("junk in "); - std::string part2("the trunk"); - const S32 CHANNEL = 0; - mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length()); - mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length()); - U8* last = 0; - const S32 BUF_LEN = 128; - char buf[BUF_LEN]; - S32 len = 11; - last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); - buf[len] = '\0'; - std::string actual(buf); - ensure_equals("first read", actual, std::string("junk in the")); - last = mBuffer.seek(CHANNEL, last, -6); - len = 12; - last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); - buf[len] = '\0'; - actual.assign(buf); - ensure_equals("seek and read", actual, std::string("in the trunk")); - } - - template<> template<> - void bas_object::test<4>() - { - std::string phrase("zippity do da!"); - const S32 CHANNEL = 0; - mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length()); - const S32 BUF_LEN = 128; - char buf[BUF_LEN]; - S32 len = 7; - U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len); - mBuffer.splitAfter(last); - LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); - LLBufferArray::segment_iterator_t end = mBuffer.endSegment(); - std::string first((char*)((*it).data()), (*it).size()); - ensure_equals("first part", first, std::string("zippity")); - ++it; - std::string second((char*)((*it).data()), (*it).size()); - ensure_equals("second part", second, std::string(" do da!")); - ++it; - ensure("iterators equal", (it == end)); - } - - template<> template<> - void bas_object::test<5>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream str(ch, &mBuffer); - std::string h1("hello"); - std::string h2(", how are you doing?"); - std::string expected(h1); - expected.append(h2); - str << h1 << h2; - str.flush(); - const S32 BUF_LEN = 128; - char buf[BUF_LEN]; - S32 actual_len = BUF_LEN; - S32 expected_len = h1.size() + h2.size(); - (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); - ensure_equals("streamed size", actual_len, expected_len); - buf[actual_len] = '\0'; - std::string actual(buf); - ensure_equals("streamed to buf", actual, expected); - } - - template<> template<> - void bas_object::test<6>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream bstr(ch, &mBuffer); - std::ostringstream ostr; - std::vector ids; - LLUUID id; - for(int i = 0; i < 5; ++i) - { - id.generate(); - ids.push_back(id); - } - bstr << "SELECT concat(u.username, ' ', l.name) " - << "FROM user u, user_last_name l " - << "WHERE u.last_name_id = l.last_name_id" - << " AND u.agent_id IN ('"; - ostr << "SELECT concat(u.username, ' ', l.name) " - << "FROM user u, user_last_name l " - << "WHERE u.last_name_id = l.last_name_id" - << " AND u.agent_id IN ('"; - std::copy( - ids.begin(), - ids.end(), - std::ostream_iterator(bstr, "','")); - std::copy( - ids.begin(), - ids.end(), - std::ostream_iterator(ostr, "','")); - bstr.seekp(-2, std::ios::cur); - ostr.seekp(-2, std::ios::cur); - bstr << ") "; - ostr << ") "; - bstr.flush(); - const S32 BUF_LEN = 512; - char buf[BUF_LEN]; /* Flawfinder: ignore */ - S32 actual_len = BUF_LEN; - (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); - buf[actual_len] = '\0'; - std::string actual(buf); - std::string expected(ostr.str()); - ensure_equals("size of string in seek",actual.size(),expected.size()); - ensure_equals("seek in ostream", actual, expected); - } - - template<> template<> - void bas_object::test<7>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream bstr(ch, &mBuffer); - bstr << "1"; - bstr.flush(); - S32 count = mBuffer.countAfter(ch.out(), NULL); - ensure_equals("buffer size 1", count, 1); - LLBufferArray buffer; - buffer.append(ch.out(), (U8*)"2", 1); - mBuffer.takeContents(buffer); - count = mBuffer.countAfter(ch.out(), NULL); - ensure_equals("buffer size 2", count, 2); - bstr << "3"; - bstr.flush(); - count = mBuffer.countAfter(ch.out(), NULL); - ensure_equals("buffer size 3", count, 3); - U8* temp = new U8[count]; - mBuffer.readAfter(ch.out(), NULL, temp, count); - ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); - delete[] temp; - } - - template<> template<> - void bas_object::test<8>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream ostr(ch, &mBuffer); - typedef std::vector buf_t; - typedef std::vector actual_t; - actual_t actual; - buf_t source; - bool need_comma = false; - ostr << "["; - S32 total_size = 1; - for(S32 i = 2000; i < 2003; ++i) - { - if(need_comma) - { - ostr << ","; - ++total_size; - } - need_comma = true; - srand(69 + i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 1000; - std::generate_n( - std::back_insert_iterator(source), - size, - rand); - actual.push_back(source); - ostr << "b(" << size << ")\""; - total_size += 8; - ostr.write((const char*)(&source[0]), size); - total_size += size; - source.clear(); - ostr << "\""; - ++total_size; - } - ostr << "]"; - ++total_size; - ostr.flush(); - - // now that we have a bunch of data on a stream, parse it all. - ch = mBuffer.nextChannel(); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("size of buffer", count, total_size); - LLBufferStream istr(ch, &mBuffer); - LLSD data; - count = LLSDSerialize::fromNotation(data, istr, total_size); - ensure("sd parsed", data.isDefined()); - - for(S32 j = 0; j < 3; ++j) - { - std::ostringstream name; - LLSD child(data[j]); - name << "found buffer " << j; - ensure(name.str(), child.isDefined()); - source = child.asBinary(); - name.str(""); - name << "buffer " << j << " size"; - ensure_equals(name.str().c_str(), source.size(), actual[j].size()); - name.str(""); - name << "buffer " << j << " contents"; - ensure( - name.str(), - (0 == memcmp(&source[0], &actual[j][0], source.size()))); - } - } - - template<> template<> - void bas_object::test<9>() - { - LLChannelDescriptors ch = mBuffer.nextChannel(); - LLBufferStream ostr(ch, &mBuffer); - typedef std::vector buf_t; - buf_t source; - bool need_comma = false; - ostr << "{"; - S32 total_size = 1; - for(S32 i = 1000; i < 3000; ++i) - { - if(need_comma) - { - ostr << ","; - ++total_size; - } - need_comma = true; - ostr << "'" << i << "':"; - total_size += 7; - srand(69 + i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 1000; - std::generate_n( - std::back_insert_iterator(source), - size, - rand); - ostr << "b(" << size << ")\""; - total_size += 8; - ostr.write((const char*)(&source[0]), size); - total_size += size; - source.clear(); - ostr << "\""; - ++total_size; - } - ostr << "}"; - ++total_size; - ostr.flush(); - - // now that we have a bunch of data on a stream, parse it all. - ch = mBuffer.nextChannel(); - S32 count = mBuffer.countAfter(ch.in(), NULL); - ensure_equals("size of buffer", count, total_size); - LLBufferStream istr(ch, &mBuffer); - LLSD data; - count = LLSDSerialize::fromNotation(data, istr, total_size); - ensure("sd parsed", data.isDefined()); - } - - template<> template<> - void bas_object::test<10>() - { + struct buffer_and_stream_data + { + LLBufferArray mBuffer; + }; + typedef test_group bas_test; + typedef bas_test::object bas_object; + tut::bas_test tbs("buffer_stream"); + + template<> template<> + void bas_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */ + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); + std::string hello; + std::string world; + str >> hello >> world; + ensure_equals("first word", hello, std::string("hello")); + ensure_equals("second word", world, std::string("world")); + } + + template<> template<> + void bas_object::test<2>() + { + std::string part1("Eat my shor"); + std::string part2("ts ho"); + std::string part3("mer"); + std::string ignore("ignore me"); + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length()); + mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length()); + mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length()); + mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length()); + std::string eat; + std::string my; + std::string shorts; + std::string homer; + str >> eat >> my >> shorts >> homer; + ensure_equals("word1", eat, std::string("Eat")); + ensure_equals("word2", my, std::string("my")); + ensure_equals("word3", shorts, std::string("shorts")); + ensure_equals("word4", homer, std::string("homer")); + } + + template<> template<> + void bas_object::test<3>() + { + std::string part1("junk in "); + std::string part2("the trunk"); + const S32 CHANNEL = 0; + mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length()); + mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length()); + U8* last = 0; + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 len = 11; + last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); + buf[len] = '\0'; + std::string actual(buf); + ensure_equals("first read", actual, std::string("junk in the")); + last = mBuffer.seek(CHANNEL, last, -6); + len = 12; + last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); + buf[len] = '\0'; + actual.assign(buf); + ensure_equals("seek and read", actual, std::string("in the trunk")); + } + + template<> template<> + void bas_object::test<4>() + { + std::string phrase("zippity do da!"); + const S32 CHANNEL = 0; + mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length()); + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 len = 7; + U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len); + mBuffer.splitAfter(last); + LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); + LLBufferArray::segment_iterator_t end = mBuffer.endSegment(); + std::string first((char*)((*it).data()), (*it).size()); + ensure_equals("first part", first, std::string("zippity")); + ++it; + std::string second((char*)((*it).data()), (*it).size()); + ensure_equals("second part", second, std::string(" do da!")); + ++it; + ensure("iterators equal", (it == end)); + } + + template<> template<> + void bas_object::test<5>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream str(ch, &mBuffer); + std::string h1("hello"); + std::string h2(", how are you doing?"); + std::string expected(h1); + expected.append(h2); + str << h1 << h2; + str.flush(); + const S32 BUF_LEN = 128; + char buf[BUF_LEN]; + S32 actual_len = BUF_LEN; + S32 expected_len = h1.size() + h2.size(); + (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); + ensure_equals("streamed size", actual_len, expected_len); + buf[actual_len] = '\0'; + std::string actual(buf); + ensure_equals("streamed to buf", actual, expected); + } + + template<> template<> + void bas_object::test<6>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream bstr(ch, &mBuffer); + std::ostringstream ostr; + std::vector ids; + LLUUID id; + for(int i = 0; i < 5; ++i) + { + id.generate(); + ids.push_back(id); + } + bstr << "SELECT concat(u.username, ' ', l.name) " + << "FROM user u, user_last_name l " + << "WHERE u.last_name_id = l.last_name_id" + << " AND u.agent_id IN ('"; + ostr << "SELECT concat(u.username, ' ', l.name) " + << "FROM user u, user_last_name l " + << "WHERE u.last_name_id = l.last_name_id" + << " AND u.agent_id IN ('"; + std::copy( + ids.begin(), + ids.end(), + std::ostream_iterator(bstr, "','")); + std::copy( + ids.begin(), + ids.end(), + std::ostream_iterator(ostr, "','")); + bstr.seekp(-2, std::ios::cur); + ostr.seekp(-2, std::ios::cur); + bstr << ") "; + ostr << ") "; + bstr.flush(); + const S32 BUF_LEN = 512; + char buf[BUF_LEN]; /* Flawfinder: ignore */ + S32 actual_len = BUF_LEN; + (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); + buf[actual_len] = '\0'; + std::string actual(buf); + std::string expected(ostr.str()); + ensure_equals("size of string in seek",actual.size(),expected.size()); + ensure_equals("seek in ostream", actual, expected); + } + + template<> template<> + void bas_object::test<7>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream bstr(ch, &mBuffer); + bstr << "1"; + bstr.flush(); + S32 count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 1", count, 1); + LLBufferArray buffer; + buffer.append(ch.out(), (U8*)"2", 1); + mBuffer.takeContents(buffer); + count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 2", count, 2); + bstr << "3"; + bstr.flush(); + count = mBuffer.countAfter(ch.out(), NULL); + ensure_equals("buffer size 3", count, 3); + U8* temp = new U8[count]; + mBuffer.readAfter(ch.out(), NULL, temp, count); + ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); + delete[] temp; + } + + template<> template<> + void bas_object::test<8>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream ostr(ch, &mBuffer); + typedef std::vector buf_t; + typedef std::vector actual_t; + actual_t actual; + buf_t source; + bool need_comma = false; + ostr << "["; + S32 total_size = 1; + for(S32 i = 2000; i < 2003; ++i) + { + if(need_comma) + { + ostr << ","; + ++total_size; + } + need_comma = true; + srand(69 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 1000; + std::generate_n( + std::back_insert_iterator(source), + size, + rand); + actual.push_back(source); + ostr << "b(" << size << ")\""; + total_size += 8; + ostr.write((const char*)(&source[0]), size); + total_size += size; + source.clear(); + ostr << "\""; + ++total_size; + } + ostr << "]"; + ++total_size; + ostr.flush(); + + // now that we have a bunch of data on a stream, parse it all. + ch = mBuffer.nextChannel(); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("size of buffer", count, total_size); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + count = LLSDSerialize::fromNotation(data, istr, total_size); + ensure("sd parsed", data.isDefined()); + + for(S32 j = 0; j < 3; ++j) + { + std::ostringstream name; + LLSD child(data[j]); + name << "found buffer " << j; + ensure(name.str(), child.isDefined()); + source = child.asBinary(); + name.str(""); + name << "buffer " << j << " size"; + ensure_equals(name.str().c_str(), source.size(), actual[j].size()); + name.str(""); + name << "buffer " << j << " contents"; + ensure( + name.str(), + (0 == memcmp(&source[0], &actual[j][0], source.size()))); + } + } + + template<> template<> + void bas_object::test<9>() + { + LLChannelDescriptors ch = mBuffer.nextChannel(); + LLBufferStream ostr(ch, &mBuffer); + typedef std::vector buf_t; + buf_t source; + bool need_comma = false; + ostr << "{"; + S32 total_size = 1; + for(S32 i = 1000; i < 3000; ++i) + { + if(need_comma) + { + ostr << ","; + ++total_size; + } + need_comma = true; + ostr << "'" << i << "':"; + total_size += 7; + srand(69 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 1000; + std::generate_n( + std::back_insert_iterator(source), + size, + rand); + ostr << "b(" << size << ")\""; + total_size += 8; + ostr.write((const char*)(&source[0]), size); + total_size += size; + source.clear(); + ostr << "\""; + ++total_size; + } + ostr << "}"; + ++total_size; + ostr.flush(); + + // now that we have a bunch of data on a stream, parse it all. + ch = mBuffer.nextChannel(); + S32 count = mBuffer.countAfter(ch.in(), NULL); + ensure_equals("size of buffer", count, total_size); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + count = LLSDSerialize::fromNotation(data, istr, total_size); + ensure("sd parsed", data.isDefined()); + } + + template<> template<> + void bas_object::test<10>() + { //#if LL_WINDOWS && _MSC_VER >= 1400 // skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); //#endif - const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {" - "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, " - "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', " - "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', " - "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', " - "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', " - "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " - "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " - "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97']," - "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M'," - "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}]," - "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', " - "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', " - "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', " - "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', " - "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', " - "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', " - "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', " - "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', " - "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', " - "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', " - "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9']," - "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0]," - "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}"; - LLChannelDescriptors ch = mBuffer.nextChannel(); - mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM)); /* Flawfinder: ignore */ - ch = mBuffer.nextChannel(); - LLBufferStream istr(ch, &mBuffer); - LLSD data; - S32 count = LLSDSerialize::fromNotation( - data, - istr, - mBuffer.count(ch.in())); - ensure("parsed something", (count > 0)); - ensure("sd parsed", data.isDefined()); - ensure_equals("sd type", data.type(), LLSD::TypeMap); - ensure("has method", data.has("method")); - ensure("has parameter", data.has("parameter")); - LLSD parameter = data["parameter"]; - ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray); - LLSD agent_params = parameter[2]; - std::string s_value; - s_value = agent_params["last_name"].asString(); - ensure_equals("last name", s_value, std::string("Linden")); - s_value = agent_params["first_name"].asString(); - ensure_equals("first name", s_value, std::string("Kelly")); - s_value = agent_params["agent_access"].asString(); - ensure_equals("agent access", s_value, std::string("M")); - s_value = agent_params["group_name"].asString(); - ensure_equals("group name", s_value, std::string("test!")); - s_value = agent_params["group_title"].asString(); - ensure_equals("group title", s_value, std::string("-> !BLING! <-")); - - LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c"); - LLUUID id = agent_params["agent_id"]; - ensure_equals("agent id", id, agent_id); - LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1"); - id = agent_params["session_id"]; - ensure_equals("session id", id, session_id); - LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652"); - id = agent_params["group_id"]; - ensure_equals("group id", id, group_id); - - S32 i_val = agent_params["limited_to_estate"]; - ensure_equals("limited to estate", i_val, 1); - i_val = agent_params["circuit_code"]; - ensure_equals("circuit code", i_val, 124); - } - - - template<> template<> - void bas_object::test<11>() - { - std::string val = "{!'foo'@:#'bar'}"; - std::istringstream istr; - istr.str(val); - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parser error return value", count, -1); - ensure("data undefined", sd.isUndefined()); - } - - template<> template<> - void bas_object::test<12>() - { + const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {" + "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, " + "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', " + "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', " + "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', " + "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', " + "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " + "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " + "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97']," + "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M'," + "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}]," + "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', " + "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', " + "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', " + "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', " + "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', " + "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', " + "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', " + "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', " + "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', " + "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', " + "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9']," + "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0]," + "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}"; + LLChannelDescriptors ch = mBuffer.nextChannel(); + mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM)); /* Flawfinder: ignore */ + ch = mBuffer.nextChannel(); + LLBufferStream istr(ch, &mBuffer); + LLSD data; + S32 count = LLSDSerialize::fromNotation( + data, + istr, + mBuffer.count(ch.in())); + ensure("parsed something", (count > 0)); + ensure("sd parsed", data.isDefined()); + ensure_equals("sd type", data.type(), LLSD::TypeMap); + ensure("has method", data.has("method")); + ensure("has parameter", data.has("parameter")); + LLSD parameter = data["parameter"]; + ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray); + LLSD agent_params = parameter[2]; + std::string s_value; + s_value = agent_params["last_name"].asString(); + ensure_equals("last name", s_value, std::string("Linden")); + s_value = agent_params["first_name"].asString(); + ensure_equals("first name", s_value, std::string("Kelly")); + s_value = agent_params["agent_access"].asString(); + ensure_equals("agent access", s_value, std::string("M")); + s_value = agent_params["group_name"].asString(); + ensure_equals("group name", s_value, std::string("test!")); + s_value = agent_params["group_title"].asString(); + ensure_equals("group title", s_value, std::string("-> !BLING! <-")); + + LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c"); + LLUUID id = agent_params["agent_id"]; + ensure_equals("agent id", id, agent_id); + LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1"); + id = agent_params["session_id"]; + ensure_equals("session id", id, session_id); + LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652"); + id = agent_params["group_id"]; + ensure_equals("group id", id, group_id); + + S32 i_val = agent_params["limited_to_estate"]; + ensure_equals("limited to estate", i_val, 1); + i_val = agent_params["circuit_code"]; + ensure_equals("circuit code", i_val, 124); + } + + + template<> template<> + void bas_object::test<11>() + { + std::string val = "{!'foo'@:#'bar'}"; + std::istringstream istr; + istr.str(val); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parser error return value", count, -1); + ensure("data undefined", sd.isUndefined()); + } + + template<> template<> + void bas_object::test<12>() + { //#if LL_WINDOWS && _MSC_VER >= 1400 // skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); //#endif - std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}"; - std::istringstream istr; - istr.str(val); - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parser error return value", count, -1); - ensure("data undefined", sd.isUndefined()); - } + std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}"; + std::istringstream istr; + istr.str(val); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parser error return value", count, -1); + ensure("data undefined", sd.isUndefined()); + } /* - template<> template<> - void bas_object::test<13>() - { - } - template<> template<> - void bas_object::test<14>() - { - } - template<> template<> - void bas_object::test<15>() - { - } + template<> template<> + void bas_object::test<13>() + { + } + template<> template<> + void bas_object::test<14>() + { + } + template<> template<> + void bas_object::test<15>() + { + } */ } namespace tut { - class PumpAndChainTestData - { - protected: - apr_pool_t* mPool; - LLPumpIO* mPump; - LLPumpIO::chain_t mChain; - - public: - PumpAndChainTestData() - { - apr_pool_create(&mPool, NULL); - mPump = new LLPumpIO(mPool); - } - - ~PumpAndChainTestData() - { - mChain.clear(); - delete mPump; - apr_pool_destroy(mPool); - } - }; - typedef test_group PumpAndChainTestGroup; - typedef PumpAndChainTestGroup::object PumpAndChainTestObject; - PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain"); - - template<> template<> - void PumpAndChainTestObject::test<1>() - { - LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); - - mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); - mChain.push_back(LLIOPipe::ptr_t(extractor)); - - LLTimer timer; - timer.setTimerExpirySec(100.0f); - - mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); - while(!extractor->done() && !timer.hasExpired()) - { - mPump->pump(); - mPump->callback(); - } - - ensure("reading string finished", extractor->done()); - ensure_equals("string was empty", extractor->string(), ""); - } + class PumpAndChainTestData + { + protected: + apr_pool_t* mPool; + LLPumpIO* mPump; + LLPumpIO::chain_t mChain; + + public: + PumpAndChainTestData() + { + apr_pool_create(&mPool, NULL); + mPump = new LLPumpIO(mPool); + } + + ~PumpAndChainTestData() + { + mChain.clear(); + delete mPump; + apr_pool_destroy(mPool); + } + }; + typedef test_group PumpAndChainTestGroup; + typedef PumpAndChainTestGroup::object PumpAndChainTestObject; + PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain"); + + template<> template<> + void PumpAndChainTestObject::test<1>() + { + LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); + + mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); + mChain.push_back(LLIOPipe::ptr_t(extractor)); + + LLTimer timer; + timer.setTimerExpirySec(100.0f); + + mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); + while(!extractor->done() && !timer.hasExpired()) + { + mPump->pump(); + mPump->callback(); + } + + ensure("reading string finished", extractor->done()); + ensure_equals("string was empty", extractor->string(), ""); + } } /* namespace tut { - struct double_construct - { - public: - double_construct() - { - LL_INFOS() << "constructed" << LL_ENDL; - } - ~double_construct() - { - LL_INFOS() << "destroyed" << LL_ENDL; - } - }; - typedef test_group double_construct_test_group; - typedef double_construct_test_group::object dc_test_object; - double_construct_test_group dctest("double construct"); - template<> template<> - void dc_test_object::test<1>() - { - ensure("test 1", true); - } + struct double_construct + { + public: + double_construct() + { + LL_INFOS() << "constructed" << LL_ENDL; + } + ~double_construct() + { + LL_INFOS() << "destroyed" << LL_ENDL; + } + }; + typedef test_group double_construct_test_group; + typedef double_construct_test_group::object dc_test_object; + double_construct_test_group dctest("double construct"); + template<> template<> + void dc_test_object::test<1>() + { + ensure("test 1", true); + } } */ namespace tut { - /** - * @brief we want to test the pipes & pumps under bad conditions. - */ - struct pipe_and_pump_fitness - { - public: - enum - { - SERVER_LISTEN_PORT = 13050 - }; - - pipe_and_pump_fitness() - { - LLFrameTimer::updateFrameTime(); - apr_pool_create(&mPool, NULL); - mPump = new LLPumpIO(mPool); - mSocket = LLSocket::create( - mPool, - LLSocket::STREAM_TCP, - SERVER_LISTEN_PORT, - "127.0.0.1"); - } - - ~pipe_and_pump_fitness() - { - mSocket.reset(); - delete mPump; - apr_pool_destroy(mPool); - } - - protected: - apr_pool_t* mPool; - LLPumpIO* mPump; - LLSocket::ptr_t mSocket; - }; - typedef test_group fitness_test_group; - typedef fitness_test_group::object fitness_test_object; - fitness_test_group fitness("pipe and pump fitness"); - - template<> template<> - void fitness_test_object::test<1>() - { - LL_DEBUGS() << "fitness_test_object::test<1>()" << LL_ENDL; - - // Set up the server - //LL_DEBUGS() << "fitness_test_object::test<1> - setting up server." - // << LL_ENDL; - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory emitter_t; - emitter_t* emitter = new emitter_t( - new LLPipeStringInjector("suckers never play me")); - std::shared_ptr factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - //LL_DEBUGS() << "fitness_test_object::test<1> - initializing server." - // << LL_ENDL; - pump_loop(mPump, 0.1f); - - // Set up the client - //LL_DEBUGS() << "fitness_test_object::test<1> - connecting client." - // << LL_ENDL; - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, 1.0f); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, 2.0f); - ensure("Did not take too long", (elapsed < 3.0f)); - } - - template<> template<> - void fitness_test_object::test<2>() - { - LL_DEBUGS() << "fitness_test_object::test<2>()" << LL_ENDL; - - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory emitter_t; - emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); - std::shared_ptr factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f); - ensure("Did not take too long", (elapsed < 3.0f)); - } - - template<> template<> - void fitness_test_object::test<3>() - { - LL_DEBUGS() << "fitness_test_object::test<3>()" << LL_ENDL; - - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory emitter_t; - emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); - std::shared_ptr factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f); - ensure("Did not take too long", (elapsed < 4.0f)); - } - - template<> template<> - void fitness_test_object::test<4>() - { - LL_DEBUGS() << "fitness_test_object::test<4>()" << LL_ENDL; - - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory emitter_t; - emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); - std::shared_ptr factory(emitter); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 1.80f); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - - // Now, the server should immediately send the data, but we'll - // never read it. pump for a bit - F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f); - ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS)); - } - - template<> template<> - void fitness_test_object::test<5>() - { - skip("Test is strongly timing dependent, " - "and on slow CI machines it fails way too often."); - const int retries = 100; - // Set up the server - LLPumpIO::chain_t chain; - typedef LLCloneIOFactory sleeper_t; - sleeper_t* sleeper = new sleeper_t(new LLIOSleeper); - std::shared_ptr factory(sleeper); - LLIOServerSocket* server = new LLIOServerSocket( - mPool, - mSocket, - factory); - server->setResponseTimeout(1.0); - chain.push_back(LLIOPipe::ptr_t(server)); - mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); - // We need to tickle the pump a little to set up the listen() - for (int retry = 0; mPump->runningChains() < 1 && retry < retries; ++retry) - { - pump_loop(mPump, 0.1f); - } - U32 count = mPump->runningChains(); - ensure_equals("server chain 1 onboard", count, 1); - LL_DEBUGS() << "** Server is up." << LL_ENDL; - - // Set up the client - LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); - LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); - bool connected = client->blockingConnect(server_host); - ensure("Connected to server", connected); - LL_DEBUGS() << "connected" << LL_ENDL; - for (int retry = 0; mPump->runningChains() < 2 && retry < retries; ++retry) - { - pump_loop(mPump,0.1f); - } - count = mPump->runningChains(); - ensure_equals("server chain 2 onboard", count, 2); - LL_DEBUGS() << "** Client is connected." << LL_ENDL; - - // We have connected, since the socket reader does not block, - // the first call to read data will return EAGAIN, so we need - // to write something. - chain.clear(); - chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); - chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); - chain.push_back(LLIOPipe::ptr_t(new LLIONull)); - mPump->addChain(chain, 0.2f); - chain.clear(); - - // pump for a bit and make sure all 3 chains are running - for (int retry = 0; mPump->runningChains() < 3 && retry < retries; ++retry) - { - pump_loop(mPump, 0.1f); - } - count = mPump->runningChains(); - ensure_equals("client chain onboard", count, 3); - LL_DEBUGS() << "** request should have been sent." << LL_ENDL; - - // pump for long enough the the client socket closes, and the - // server socket should not be closed yet. - for (int retry = 0; mPump->runningChains() == 3 && retry < retries; ++retry) - { - pump_loop(mPump, 0.1f); - } - // We used to test for count == 2 here, but on a slow test machine it - // can happen that not just one but two chains close before we reach - // this point. - count = mPump->runningChains(); - ensure(stringize("client chain timed out: count ", count), count < 3); - LL_DEBUGS() << "** client chain should be closed." << LL_ENDL; - - // At this point, the socket should be closed by the timeout - for (int retry = 0; mPump->runningChains() > 1 && retry < retries; ++retry) - { - pump_loop(mPump, 0.1f); - } - count = mPump->runningChains(); - ensure_equals("accepted socked close", count, 1); - LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL; - } + /** + * @brief we want to test the pipes & pumps under bad conditions. + */ + struct pipe_and_pump_fitness + { + public: + enum + { + SERVER_LISTEN_PORT = 13050 + }; + + pipe_and_pump_fitness() + { + LLFrameTimer::updateFrameTime(); + apr_pool_create(&mPool, NULL); + mPump = new LLPumpIO(mPool); + mSocket = LLSocket::create( + mPool, + LLSocket::STREAM_TCP, + SERVER_LISTEN_PORT, + "127.0.0.1"); + } + + ~pipe_and_pump_fitness() + { + mSocket.reset(); + delete mPump; + apr_pool_destroy(mPool); + } + + protected: + apr_pool_t* mPool; + LLPumpIO* mPump; + LLSocket::ptr_t mSocket; + }; + typedef test_group fitness_test_group; + typedef fitness_test_group::object fitness_test_object; + fitness_test_group fitness("pipe and pump fitness"); + + template<> template<> + void fitness_test_object::test<1>() + { + LL_DEBUGS() << "fitness_test_object::test<1>()" << LL_ENDL; + + // Set up the server + //LL_DEBUGS() << "fitness_test_object::test<1> - setting up server." + // << LL_ENDL; + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory emitter_t; + emitter_t* emitter = new emitter_t( + new LLPipeStringInjector("suckers never play me")); + std::shared_ptr factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + //LL_DEBUGS() << "fitness_test_object::test<1> - initializing server." + // << LL_ENDL; + pump_loop(mPump, 0.1f); + + // Set up the client + //LL_DEBUGS() << "fitness_test_object::test<1> - connecting client." + // << LL_ENDL; + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, 1.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, 2.0f); + ensure("Did not take too long", (elapsed < 3.0f)); + } + + template<> template<> + void fitness_test_object::test<2>() + { + LL_DEBUGS() << "fitness_test_object::test<2>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f); + ensure("Did not take too long", (elapsed < 3.0f)); + } + + template<> template<> + void fitness_test_object::test<3>() + { + LL_DEBUGS() << "fitness_test_object::test<3>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f); + ensure("Did not take too long", (elapsed < 4.0f)); + } + + template<> template<> + void fitness_test_object::test<4>() + { + LL_DEBUGS() << "fitness_test_object::test<4>()" << LL_ENDL; + + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory emitter_t; + emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); + std::shared_ptr factory(emitter); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 1.80f); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // We need to tickle the pump a little to set up the listen() + pump_loop(mPump, 0.1f); + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + + // Now, the server should immediately send the data, but we'll + // never read it. pump for a bit + F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f); + ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS)); + } + + template<> template<> + void fitness_test_object::test<5>() + { + skip("Test is strongly timing dependent, " + "and on slow CI machines it fails way too often."); + const int retries = 100; + // Set up the server + LLPumpIO::chain_t chain; + typedef LLCloneIOFactory sleeper_t; + sleeper_t* sleeper = new sleeper_t(new LLIOSleeper); + std::shared_ptr factory(sleeper); + LLIOServerSocket* server = new LLIOServerSocket( + mPool, + mSocket, + factory); + server->setResponseTimeout(1.0); + chain.push_back(LLIOPipe::ptr_t(server)); + mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); + // We need to tickle the pump a little to set up the listen() + for (int retry = 0; mPump->runningChains() < 1 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + U32 count = mPump->runningChains(); + ensure_equals("server chain 1 onboard", count, 1); + LL_DEBUGS() << "** Server is up." << LL_ENDL; + + // Set up the client + LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); + LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); + bool connected = client->blockingConnect(server_host); + ensure("Connected to server", connected); + LL_DEBUGS() << "connected" << LL_ENDL; + for (int retry = 0; mPump->runningChains() < 2 && retry < retries; ++retry) + { + pump_loop(mPump,0.1f); + } + count = mPump->runningChains(); + ensure_equals("server chain 2 onboard", count, 2); + LL_DEBUGS() << "** Client is connected." << LL_ENDL; + + // We have connected, since the socket reader does not block, + // the first call to read data will return EAGAIN, so we need + // to write something. + chain.clear(); + chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); + chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); + chain.push_back(LLIOPipe::ptr_t(new LLIONull)); + mPump->addChain(chain, 0.2f); + chain.clear(); + + // pump for a bit and make sure all 3 chains are running + for (int retry = 0; mPump->runningChains() < 3 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + count = mPump->runningChains(); + ensure_equals("client chain onboard", count, 3); + LL_DEBUGS() << "** request should have been sent." << LL_ENDL; + + // pump for long enough the the client socket closes, and the + // server socket should not be closed yet. + for (int retry = 0; mPump->runningChains() == 3 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + // We used to test for count == 2 here, but on a slow test machine it + // can happen that not just one but two chains close before we reach + // this point. + count = mPump->runningChains(); + ensure(stringize("client chain timed out: count ", count), count < 3); + LL_DEBUGS() << "** client chain should be closed." << LL_ENDL; + + // At this point, the socket should be closed by the timeout + for (int retry = 0; mPump->runningChains() > 1 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + count = mPump->runningChains(); + ensure_equals("accepted socked close", count, 1); + LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL; + } } /* diff --git a/indra/test/lltut.h b/indra/test/lltut.h index 4ce450057c..fbf60444be 100644 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -1,4 +1,4 @@ -/** +/** * @file lltut.h * @author Phoenix * @date 2005-09-26 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&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$ */ @@ -40,35 +40,35 @@ class LLURI; namespace tut { - void ensure_equals(const std::string& msg, - const LLDate& actual, const LLDate& expected); + void ensure_equals(const std::string& msg, + const LLDate& actual, const LLDate& expected); - void ensure_equals(const std::string& msg, - const LLURI& actual, const LLURI& expected); + void ensure_equals(const std::string& msg, + const LLURI& actual, const LLURI& expected); - // std::vector is the current definition of LLSD::Binary. Because - // we're only forward-declaring LLSD in this header file, we can't - // directly reference that nested type. If the build complains that - // there's no definition for this declaration, it could be that - // LLSD::Binary has changed, and that this declaration must be adjusted to - // match. - void ensure_equals(const std::string& msg, - const std::vector& actual, const std::vector& expected); + // std::vector is the current definition of LLSD::Binary. Because + // we're only forward-declaring LLSD in this header file, we can't + // directly reference that nested type. If the build complains that + // there's no definition for this declaration, it could be that + // LLSD::Binary has changed, and that this declaration must be adjusted to + // match. + void ensure_equals(const std::string& msg, + const std::vector& actual, const std::vector& expected); - void ensure_equals(const std::string& msg, - const LLSD& actual, const LLSD& expected); + void ensure_equals(const std::string& msg, + const LLSD& actual, const LLSD& expected); - void ensure_starts_with(const std::string& msg, - const std::string& actual, const std::string& expectedStart); + void ensure_starts_with(const std::string& msg, + const std::string& actual, const std::string& expectedStart); - void ensure_ends_with(const std::string& msg, - const std::string& actual, const std::string& expectedEnd); + void ensure_ends_with(const std::string& msg, + const std::string& actual, const std::string& expectedEnd); - void ensure_contains(const std::string& msg, - const std::string& actual, const std::string& expectedSubString); + void ensure_contains(const std::string& msg, + const std::string& actual, const std::string& expectedSubString); - void ensure_does_not_contain(const std::string& msg, - const std::string& actual, const std::string& expectedSubString); + void ensure_does_not_contain(const std::string& msg, + const std::string& actual, const std::string& expectedSubString); } // This is an odd place to #include an important contributor -- but the usual @@ -89,73 +89,73 @@ namespace tut // The functions BELOW this point actually consume tut.hpp functionality. namespace tut { - inline void ensure_approximately_equals(const char* msg, F64 actual, F64 expected, U32 frac_bits) - { - if(!is_approx_equal_fraction(actual, expected, frac_bits)) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_approximately_equals(const char* msg, F32 actual, F32 expected, U32 frac_bits) - { - if(!is_approx_equal_fraction(actual, expected, frac_bits)) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_approximately_equals(F32 actual, F32 expected, U32 frac_bits) - { - ensure_approximately_equals(NULL, actual, expected, frac_bits); - } - - inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta) - { - if (fabs(actual-expected)>delta) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len) - { - if((expected_len != actual_len) || - (std::memcmp(actual, expected, actual_len) != 0)) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "not equal"; - throw tut::failure(ss.str().c_str()); - } - } - - inline void ensure_memory_matches(const void* actual, U32 actual_len, const void* expected,U32 expected_len) - { - ensure_memory_matches(NULL, actual, actual_len, expected, expected_len); - } - - template - void ensure_not_equals(const char* msg,const Q& actual,const T& expected) - { - if( expected == actual ) - { - std::stringstream ss; - ss << (msg?msg:"") << (msg?": ":"") << "both equal " << expected; - throw tut::failure(ss.str().c_str()); - } - } - - template - void ensure_not_equals(const Q& actual,const T& expected) - { - ensure_not_equals(NULL, actual, expected); - } + inline void ensure_approximately_equals(const char* msg, F64 actual, F64 expected, U32 frac_bits) + { + if(!is_approx_equal_fraction(actual, expected, frac_bits)) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_approximately_equals(const char* msg, F32 actual, F32 expected, U32 frac_bits) + { + if(!is_approx_equal_fraction(actual, expected, frac_bits)) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_approximately_equals(F32 actual, F32 expected, U32 frac_bits) + { + ensure_approximately_equals(NULL, actual, expected, frac_bits); + } + + inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta) + { + if (fabs(actual-expected)>delta) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len) + { + if((expected_len != actual_len) || + (std::memcmp(actual, expected, actual_len) != 0)) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "not equal"; + throw tut::failure(ss.str().c_str()); + } + } + + inline void ensure_memory_matches(const void* actual, U32 actual_len, const void* expected,U32 expected_len) + { + ensure_memory_matches(NULL, actual, actual_len, expected, expected_len); + } + + template + void ensure_not_equals(const char* msg,const Q& actual,const T& expected) + { + if( expected == actual ) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "both equal " << expected; + throw tut::failure(ss.str().c_str()); + } + } + + template + void ensure_not_equals(const Q& actual,const T& expected) + { + ensure_not_equals(NULL, actual, expected); + } } #endif // LL_LLTUT_H -- cgit v1.2.3 From 65bd23651d97722cd3777c2716c010ee14bd9ec7 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 13:46:57 -0400 Subject: Fix missing #include in lltextvalidate.cpp --- indra/llui/lltextvalidate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 9e27ed6232..10b3be1c23 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -31,6 +31,7 @@ #include "lltextvalidate.h" #include "llnotificationsutil.h" +#include "lltimer.h" #include "lltrans.h" #include "llresmgr.h" // for LLLocale -- cgit v1.2.3 From 2c118b53e20cd9bad07407c584ca0bcf92b9af1d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 22 May 2024 10:50:31 -0400 Subject: WIP: Trying to diagnose and fix test program shutdown crash --- indra/llcommon/lazyeventapi.cpp | 4 ++- indra/llcommon/llinstancetracker.h | 35 ++----------------- indra/llcommon/llsingleton.cpp | 43 ++++++++++++++++++----- indra/llcommon/llsingleton.h | 9 ++++- indra/llcommon/lockstatic.h | 71 +++++++++++++++++++++++++++++++------- indra/test/writestr.h | 39 +++++++++++++++++++++ 6 files changed, 146 insertions(+), 55 deletions(-) create mode 100755 indra/test/writestr.h diff --git a/indra/llcommon/lazyeventapi.cpp b/indra/llcommon/lazyeventapi.cpp index 91db0ee4a6..eebed374c3 100644 --- a/indra/llcommon/lazyeventapi.cpp +++ b/indra/llcommon/lazyeventapi.cpp @@ -47,7 +47,9 @@ LL::LazyEventAPIBase::~LazyEventAPIBase() // case, do NOT unregister their name out from under them! // If this is a static instance being destroyed at process shutdown, // LLEventPumps will probably have been cleaned up already. - if (mRegistered && ! LLEventPumps::wasDeleted()) + // That said, in a test program, LLEventPumps might never have been + // constructed to start with. + if (mRegistered && LLEventPumps::instanceExists()) { // unregister the callback to this doomed instance LLEventPumps::instance().unregisterPumpFactory(mParams.name); diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 921f743ada..aba9f1187b 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -80,6 +80,8 @@ class LLInstanceTracker { InstanceMap mMap; }; + // Unfortunately there's no umbrella class that owns all LLInstanceTracker + // instances, so there's no good place to call LockStatic::cleanup(). typedef llthread::LockStatic LockStatic; public: @@ -169,23 +171,7 @@ public: } // lock static data during construction -#if ! LL_WINDOWS LockStatic mLock; -#else // LL_WINDOWS - // We want to be able to use (e.g.) our instance_snapshot subclass as: - // for (auto& inst : T::instance_snapshot()) ... - // But when this snapshot base class directly contains LockStatic, as - // above, Visual Studio 2017 requires us to code instead: - // for (auto& inst : std::move(T::instance_snapshot())) ... - // nat thinks this should be unnecessary, as an anonymous class - // instance is already a temporary. It shouldn't need to be cast to - // rvalue reference (the role of std::move()). clang evidently agrees, - // as the short form works fine with Xcode on Mac. - // To support the succinct usage, instead of directly storing - // LockStatic, store std::shared_ptr, which is copyable. - std::shared_ptr mLockp{std::make_shared()}; - LockStatic& mLock{*mLockp}; -#endif // LL_WINDOWS VectorType mData; }; using snapshot = snapshot_of; @@ -384,6 +370,7 @@ class LLInstanceTracker { InstanceSet mSet; }; + // see LockStatic comment in the above specialization for non-void KEY typedef llthread::LockStatic LockStatic; public: @@ -461,23 +448,7 @@ public: } // lock static data during construction -#if ! LL_WINDOWS LockStatic mLock; -#else // LL_WINDOWS - // We want to be able to use our instance_snapshot subclass as: - // for (auto& inst : T::instance_snapshot()) ... - // But when this snapshot base class directly contains LockStatic, as - // above, Visual Studio 2017 requires us to code instead: - // for (auto& inst : std::move(T::instance_snapshot())) ... - // nat thinks this should be unnecessary, as an anonymous class - // instance is already a temporary. It shouldn't need to be cast to - // rvalue reference (the role of std::move()). clang evidently agrees, - // as the short form works fine with Xcode on Mac. - // To support the succinct usage, instead of directly storing - // LockStatic, store std::shared_ptr, which is copyable. - std::shared_ptr mLockp{std::make_shared()}; - LockStatic& mLock{*mLockp}; -#endif // LL_WINDOWS VectorType mData; }; using snapshot = snapshot_of; diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 0acf9513d8..3049e81139 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -33,6 +33,7 @@ #include "llerrorcontrol.h" #include "llexception.h" #include "llmainthreadtask.h" +#include "../test/writestr.h" #include #include // std::cerr in dire emergency #include @@ -64,6 +65,12 @@ private: mutex_t mMutex; +public: + ~MasterList() + { + writestr(2, "~MasterList()"); + } + public: // Instantiate this to both obtain a reference to MasterList::instance() // and lock its mutex for the lifespan of this Lock instance. @@ -147,6 +154,7 @@ public: private: list_t& get_initializing_() { + writestr(2, "MasterList::get_initializing_()"); LLSingletonBase::list_t* current = mInitializing.get(); if (! current) { @@ -163,6 +171,7 @@ private: // we pop the list to empty, reset() the running coroutine's local_ptr. void cleanup_initializing_() { + writestr(2, "MasterList::cleanup_initializing_()"); mInitializing.reset(nullptr); } }; @@ -272,17 +281,33 @@ void LLSingletonBase::reset_initializing(list_t::size_type size) void LLSingletonBase::MasterList::LockedInitializing::log(const char* verb, const char* name) { - LL_DEBUGS("LLSingleton") << verb << ' ' << demangle(name) << ';'; - if (mList) + LL_DEBUGS("LLSingleton") << verb << ' ' << demangle(name) << ';'; + if (mList) + { + for (list_t::const_reverse_iterator ri(mList->rbegin()), rend(mList->rend()); + ri != rend; ++ri) { - for (list_t::const_reverse_iterator ri(mList->rbegin()), rend(mList->rend()); - ri != rend; ++ri) - { - LLSingletonBase* sb(*ri); - LL_CONT << ' ' << classname(sb); - } + LLSingletonBase* sb(*ri); + LL_CONT << ' ' << classname(sb); } - LL_ENDL; + } + LL_ENDL; +} + +void LLSingletonBase::capture_dependency(LLSingletonBase* sb) +{ + // If we're called very late during application shutdown, the Boost.Fibers + // library may have shut down, and MasterList::mInitializing.get() might + // blow up. But if we're called that late, there's really no point in + // trying to capture this dependency. + writestr(2, "LLSingletonBase::capture_dependency() trampoline"); + if (boost::fibers::context::active()) + { + writestr(2, "still active"); + sb->capture_dependency(); + } + else + writestr(2, "no longer active"); } void LLSingletonBase::capture_dependency() diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 25afccccc0..f44dcd77a8 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -112,6 +112,8 @@ protected: // If a given call to B::getInstance() happens during either A::A() or // A::initSingleton(), record that A directly depends on B. void capture_dependency(); + // trampoline to non-static member function + static void capture_dependency(LLSingletonBase*); // delegate logging calls to llsingleton.cpp public: @@ -202,7 +204,7 @@ struct LLSingleton_manage_master } void capture_dependency(LLSingletonBase* sb) { - sb->capture_dependency(); + LLSingletonBase::capture_dependency(sb); } }; @@ -434,6 +436,11 @@ protected: // Remove this instance from the master list. LLSingleton_manage_master().remove(this); + // We should no longer need our LockStatic -- but the fact that we can + // query or even resurrect a deleted LLSingleton means we basically + // have to shrug and leak our SingletonData. It's not large, and this + // only happens at shutdown anyway. +// lk.cleanup(); } public: diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h index 7cc9b7eec0..35160521a7 100644 --- a/indra/llcommon/lockstatic.h +++ b/indra/llcommon/lockstatic.h @@ -14,6 +14,8 @@ #define LL_LOCKSTATIC_H #include "mutex.h" // std::unique_lock +#include "llerror.h" +#include "llexception.h" namespace llthread { @@ -26,9 +28,15 @@ class LockStatic { typedef std::unique_lock lock_t; public: + // trying to lock Static after cleanup() has been called + struct Dead: public LLException + { + Dead(const std::string& what): LLException(what) {} + }; + LockStatic(): mData(getStatic()), - mLock(mData->mMutex) + mLock(getLock(mData)) {} Static* get() const { return mData; } operator Static*() const { return get(); } @@ -40,31 +48,70 @@ public: mData = nullptr; mLock.unlock(); } + // explicit destruction + // We used to store a static instance of Static in getStatic(). The + // trouble with that is that at some point during final termination + // cleanup, the compiler calls ~Static(), destroying the mutex. If some + // later static object's destructor tries to lock our Static, we blow up + // trying to lock a destroyed mutex object. This can happen, for instance, + // if some class's destructor tries to reference an LLSingleton. + // Since a plain dumb pointer has no destructor, the compiler leaves it + // alone, so the referenced heap Static instance can survive until we + // explicitly call this method. + void cleanup() + { + // certainly don't claim to lock after this point! + mData = nullptr; + Static*& ptrref{ getStatic() }; + Static* ptr{ ptrref }; + ptrref = nullptr; + delete ptr; + } protected: Static* mData; lock_t mLock; private: - Static* getStatic() + static lock_t getLock(Static* data) + { + // data can be false if cleanup() has already been called. If so, no + // code in the caller is valid that depends on this instance. We dare + // to throw an exception because trying to lock Static after it's been + // deleted is not part of normal processing. There are callers who + // want to handle this exception, but it should indeed be treated as + // exceptional. + if (! data) + { + LLTHROW(Dead("LockStatic<" + LLError::Log::classname>() + + "> called after cleanup()")); + } + // Usual case: data isn't nullptr, carry on. + return lock_t(data->mMutex); + } + + Static*& getStatic() { - // Static::mMutex must be function-local static rather than class- - // static. Some of our consumers must function properly (therefore - // lock properly) even when the containing module's static variables - // have not yet been runtime-initialized. A mutex requires + // Our Static instance must be function-local static rather than + // class-static. Some of our consumers must function properly + // (therefore lock properly) even when the containing module's static + // variables have not yet been runtime-initialized. A mutex requires // construction. A static class member might not yet have been // constructed. // - // We could store a dumb mutex_t*, notice when it's NULL and allocate a - // heap mutex -- but that's vulnerable to race conditions. And we can't - // defend the dumb pointer with another mutex. + // We could store a dumb mutex_t* class member, notice when it's NULL + // and allocate a heap mutex -- but that's vulnerable to race + // conditions. And we can't defend the dumb pointer with another + // mutex. // // We could store a std::atomic -- but a default-constructed // std::atomic does not contain a valid T, even a default-constructed // T! Which means std::atomic, too, requires runtime initialization. // // But a function-local static is guaranteed to be initialized exactly - // once: the first time control reaches that declaration. - static Static sData; - return &sData; + // once: the first time control reaches that declaration. Importantly, + // since a plain dumb pointer has no destructor, the compiler lets our + // heap Static instance survive until someone calls cleanup() (above). + static Static* sData{ new Static }; + return sData; } }; diff --git a/indra/test/writestr.h b/indra/test/writestr.h new file mode 100755 index 0000000000..df1dab2f10 --- /dev/null +++ b/indra/test/writestr.h @@ -0,0 +1,39 @@ +/** + * @file writestr.h + * @author Nat Goodspeed + * @date 2024-05-21 + * @brief writestr() function for when iostream isn't set up + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_WRITESTR_H) +#define LL_WRITESTR_H + +#include "stringize.h" + +#ifndef LL_WINDOWS + +#include + +#else // LL_WINDOWS + +#include +inline +int write(int fd, const void* buffer, unsigned int count) +{ + return _write(fd, buffer, count); +} + +#endif // LL_WINDOWS + +template +auto writestr(int fd, ARGS&&... args) +{ + std::string str{ stringize(std::forward(args)..., '\n') }; + return write(fd, str.data(), str.length()); +} + +#endif /* ! defined(LL_WRITESTR_H) */ -- cgit v1.2.3 From 796ebd3c5491a607059d8a7db489fefb5731cb4d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2024 11:41:28 -0400 Subject: Fix test program termination crash. --- indra/llcommon/CMakeLists.txt | 27 ++++++++++++++------------- indra/llcommon/llsingleton.cpp | 13 ------------- indra/llcommon/lockstatic.cpp | 26 ++++++++++++++++++++++++++ indra/llcommon/lockstatic.h | 24 +++++++++++++++--------- 4 files changed, 55 insertions(+), 35 deletions(-) create mode 100755 indra/llcommon/lockstatic.cpp diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index f9353baa4d..d5440d6bc8 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -18,6 +18,7 @@ include(Tracy) set(llcommon_SOURCE_FILES apply.cpp commoncontrol.cpp + hbxxh.cpp indra_constants.cpp lazyeventapi.cpp llallocator.cpp @@ -58,8 +59,8 @@ set(llcommon_SOURCE_FILES llframetimer.cpp llheartbeat.cpp llheteromap.cpp - llinitparam.cpp llinitdestroyclass.cpp + llinitparam.cpp llinstancetracker.cpp llkeybind.cpp llleap.cpp @@ -69,15 +70,15 @@ set(llcommon_SOURCE_FILES llmd5.cpp llmemory.cpp llmemorystream.cpp - llmetrics.cpp llmetricperformancetester.cpp + llmetrics.cpp llmortician.cpp llmutex.cpp - llptrto.cpp llpredicate.cpp llprocess.cpp llprocessor.cpp llprocinfo.cpp + llptrto.cpp llqueuedthread.cpp llrand.cpp llrefcount.cpp @@ -107,11 +108,11 @@ set(llcommon_SOURCE_FILES lluriparser.cpp lluuid.cpp llworkerthread.cpp + lockstatic.cpp lua_function.cpp lualistener.cpp - hbxxh.cpp - u64.cpp threadpool.cpp + u64.cpp workqueue.cpp StackWalker.cpp ) @@ -128,6 +129,7 @@ set(llcommon_HEADER_FILES fix_macros.h fsyspath.h function_types.h + hbxxh.h indra_constants.h lazyeventapi.h linden_common.h @@ -165,9 +167,9 @@ set(llcommon_HEADER_FILES lleventapi.h lleventcoro.h lleventdispatcher.h + lleventemitter.h lleventfilter.h llevents.h - lleventemitter.h llexception.h llfasttimer.h llfile.h @@ -194,13 +196,11 @@ set(llcommon_HEADER_FILES llmd5.h llmemory.h llmemorystream.h - llmetrics.h llmetricperformancetester.h + llmetrics.h llmortician.h llnametable.h llpointer.h - llprofiler.h - llprofilercategories.h llpounceable.h llpredicate.h llpreprocessor.h @@ -208,6 +208,8 @@ set(llcommon_HEADER_FILES llprocess.h llprocessor.h llprocinfo.h + llprofiler.h + llprofilercategories.h llptrto.h llqueuedthread.h llrand.h @@ -225,14 +227,14 @@ set(llcommon_HEADER_FILES llsimplehash.h llsingleton.h llstacktrace.h + llstaticstringtable.h + llstatsaccumulator.h llstl.h llstreamqueue.h llstreamtools.h llstrider.h llstring.h llstringtable.h - llstaticstringtable.h - llstatsaccumulator.h llsys.h lltempredirect.h llthread.h @@ -252,10 +254,9 @@ set(llcommon_HEADER_FILES llwin32headers.h llwin32headerslean.h llworkerthread.h + lockstatic.h lua_function.h lualistener.h - hbxxh.h - lockstatic.h stdtypes.h stringize.h threadpool.h diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 3049e81139..5b0990e213 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -33,7 +33,6 @@ #include "llerrorcontrol.h" #include "llexception.h" #include "llmainthreadtask.h" -#include "../test/writestr.h" #include #include // std::cerr in dire emergency #include @@ -65,12 +64,6 @@ private: mutex_t mMutex; -public: - ~MasterList() - { - writestr(2, "~MasterList()"); - } - public: // Instantiate this to both obtain a reference to MasterList::instance() // and lock its mutex for the lifespan of this Lock instance. @@ -154,7 +147,6 @@ public: private: list_t& get_initializing_() { - writestr(2, "MasterList::get_initializing_()"); LLSingletonBase::list_t* current = mInitializing.get(); if (! current) { @@ -171,7 +163,6 @@ private: // we pop the list to empty, reset() the running coroutine's local_ptr. void cleanup_initializing_() { - writestr(2, "MasterList::cleanup_initializing_()"); mInitializing.reset(nullptr); } }; @@ -300,14 +291,10 @@ void LLSingletonBase::capture_dependency(LLSingletonBase* sb) // library may have shut down, and MasterList::mInitializing.get() might // blow up. But if we're called that late, there's really no point in // trying to capture this dependency. - writestr(2, "LLSingletonBase::capture_dependency() trampoline"); if (boost::fibers::context::active()) { - writestr(2, "still active"); sb->capture_dependency(); } - else - writestr(2, "no longer active"); } void LLSingletonBase::capture_dependency() diff --git a/indra/llcommon/lockstatic.cpp b/indra/llcommon/lockstatic.cpp new file mode 100755 index 0000000000..b647208724 --- /dev/null +++ b/indra/llcommon/lockstatic.cpp @@ -0,0 +1,26 @@ +/** + * @file lockstatic.cpp + * @author Nat Goodspeed + * @date 2024-05-23 + * @brief Implementation for lockstatic. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lockstatic.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llerror.h" +#include "stringize.h" + +void llthread::LockStaticBase::throwDead(const char* mangled) +{ + LLTHROW(Dead(stringize(LLError::Log::demangle(mangled), " called after cleanup()"))); +} diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h index 35160521a7..e83957b1fd 100644 --- a/indra/llcommon/lockstatic.h +++ b/indra/llcommon/lockstatic.h @@ -14,19 +14,14 @@ #define LL_LOCKSTATIC_H #include "mutex.h" // std::unique_lock -#include "llerror.h" #include "llexception.h" +#include namespace llthread { -// Instantiate this template to obtain a pointer to the canonical static -// instance of Static while holding a lock on that instance. Use of -// Static::mMutex presumes that Static declares some suitable mMutex. -template -class LockStatic +class LockStaticBase { - typedef std::unique_lock lock_t; public: // trying to lock Static after cleanup() has been called struct Dead: public LLException @@ -34,6 +29,18 @@ public: Dead(const std::string& what): LLException(what) {} }; +protected: + static void throwDead(const char* mangled); +}; + +// Instantiate this template to obtain a pointer to the canonical static +// instance of Static while holding a lock on that instance. Use of +// Static::mMutex presumes that Static declares some suitable mMutex. +template +class LockStatic: public LockStaticBase +{ + typedef std::unique_lock lock_t; +public: LockStatic(): mData(getStatic()), mLock(getLock(mData)) @@ -81,8 +88,7 @@ private: // exceptional. if (! data) { - LLTHROW(Dead("LockStatic<" + LLError::Log::classname>() + - "> called after cleanup()")); + throwDead(typeid(LockStatic).name()); } // Usual case: data isn't nullptr, carry on. return lock_t(data->mMutex); -- cgit v1.2.3 From f4b80ccdb2a81cbc2e6a175dd711f38aa93d206f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2024 12:59:18 -0400 Subject: Fix lingering trailing whitespace in lleventfilter.h. --- indra/llcommon/lleventfilter.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index b39791c560..9988459aae 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-05 * @brief Define LLEventFilter: LLEventStream subclass with conditions - * + * * $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$ */ @@ -79,8 +79,8 @@ private: /** * Wait for an event to be posted. If no such event arrives within a specified * time, take a specified action. - * - * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) + * + * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) * constructor to ensure that the upstream event pump is not an LLEventMaildrop * or any other kind of store and forward pump which may have events outstanding. * Using this constructor will cause the upstream event pump to fire any pending @@ -154,11 +154,11 @@ public: /** * Like actionAfter(), but where the desired Action is a particular event * for all listeners. Pass the timeout time and the desired @a event data. - * + * * Suppose the timeout should only be satisfied by a particular event, but * the ultimate listener must see all other incoming events as well, plus * the timeout @a event if any: - * + * * @code * some LLEventMatching LLEventMatching * event ---> for particular ---> LLEventTimeout ---> for timeout @@ -166,7 +166,7 @@ public: * \ \ ultimate * `-----------------------------------------------------> listener * @endcode - * + * * Since a given listener can listen on more than one LLEventPump, we can * set things up so it sees the set union of events from LLEventTimeout * and the original event source. However, as LLEventTimeout passes -- cgit v1.2.3 From 9d1c850a39fecaedfc93b3a6d4434f520aab6621 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2024 13:00:58 -0400 Subject: Fix lingering trailing whitespace in lleventfilter.cpp. --- indra/llcommon/lleventfilter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index ad61e9298a..da19946e3b 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-05 * @brief Implementation for lleventfilter. - * + * * $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$ */ -- cgit v1.2.3 From 0abaa812df83dd803a8faba5c222630415816291 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2024 13:09:01 -0400 Subject: Fix lingering trailing whitespace in llmainthreadtask.h. --- indra/llcommon/llmainthreadtask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llmainthreadtask.h b/indra/llcommon/llmainthreadtask.h index dde6c20210..eccf11fcbe 100644 --- a/indra/llcommon/llmainthreadtask.h +++ b/indra/llcommon/llmainthreadtask.h @@ -4,7 +4,7 @@ * @date 2019-12-04 * @brief LLMainThreadTask dispatches work to the main thread. When invoked on * the main thread, it performs the work inline. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ -- cgit v1.2.3 From 91a549fb1fca4924dec33a6206990b7d098cfd4e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2024 13:26:38 -0400 Subject: More vestigial whitespace fixes --- indra/llcommon/llsingleton.cpp | 16 ++++++++-------- indra/llcommon/llsingleton.h | 12 ++++++------ indra/llcommon/tests/llmainthreadtask_test.cpp | 2 +- indra/llcommon/tests/llprocess_test.cpp | 4 ++-- indra/newview/lllocalgltfmaterials.cpp | 16 ++++++++-------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 5b0990e213..02ff02cedc 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsingleton.cpp * @author Brad Kittenbrink * * $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$ */ @@ -290,7 +290,7 @@ void LLSingletonBase::capture_dependency(LLSingletonBase* sb) // If we're called very late during application shutdown, the Boost.Fibers // library may have shut down, and MasterList::mInitializing.get() might // blow up. But if we're called that late, there's really no point in - // trying to capture this dependency. + // trying to capture this dependency. if (boost::fibers::context::active()) { sb->capture_dependency(); @@ -376,7 +376,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort() // should happen basically once: for deleteAll(). typedef LLDependencies SingletonDeps; SingletonDeps sdeps; - // Lock while traversing the master list + // Lock while traversing the master list MasterList::LockedMaster master; for (LLSingletonBase* sp : master.get()) { @@ -468,7 +468,7 @@ std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params return out; } -} // anonymous namespace +} // anonymous namespace //static void LLSingletonBase::logwarns(const string_params& args) diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index f44dcd77a8..6b20b4dac0 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -1,24 +1,24 @@ -/** +/** * @file llsingleton.h * * $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$ */ @@ -858,7 +858,7 @@ private: \ // Relatively unsafe singleton implementation that is much faster // and simpler than LLSingleton, but has no dependency tracking -// or inherent thread safety and requires manual invocation of +// or inherent thread safety and requires manual invocation of // createInstance before first use. template class LLSimpleton diff --git a/indra/llcommon/tests/llmainthreadtask_test.cpp b/indra/llcommon/tests/llmainthreadtask_test.cpp index 4a15e30a30..ea4232ad78 100644 --- a/indra/llcommon/tests/llmainthreadtask_test.cpp +++ b/indra/llcommon/tests/llmainthreadtask_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-05 * @brief Test for llmainthreadtask. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index deef717e5c..9b3b345217 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-12-19 * @brief Test for llprocess. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ @@ -1076,7 +1076,7 @@ namespace tut { EventListener(LLEventPump& pump) { - mConnection = + mConnection = pump.listen("EventListener", boost::bind(&EventListener::tick, this, _1)); } diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp index 91753349c8..8019be6f42 100644 --- a/indra/newview/lllocalgltfmaterials.cpp +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lllocalrendermaterials.cpp * @brief Local GLTF materials source * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, 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$ */ @@ -51,14 +51,14 @@ /*=======================================*/ /* Formal declarations, constants, etc. */ -/*=======================================*/ +/*=======================================*/ static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; static const S32 LL_LOCAL_UPDATE_RETRIES = 5; /*=======================================*/ /* LLLocalGLTFMaterial: unit class */ -/*=======================================*/ +/*=======================================*/ LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename, S32 index) : mFilename(filename) , mShortName(gDirUtilp->getBaseFileName(filename, true)) @@ -298,7 +298,7 @@ void LLLocalGLTFMaterialTimer::stopTimer() bool LLLocalGLTFMaterialTimer::tick() { - // todo: do on idle? No point in timer + // todo: do on idle? No point in timer LLLocalGLTFMaterialMgr::getInstance()->doUpdates(); return false; } -- cgit v1.2.3 From e2f179b9edebca1557ce3f774781bb9b9350b781 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2024 15:02:12 -0400 Subject: Remove commented-out methods in a couple LLEventTimer subclasses. --- indra/newview/llappearancemgr.cpp | 3 --- indra/newview/lltoast.cpp | 9 --------- indra/newview/lltoast.h | 2 -- 3 files changed, 14 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 734ee277bf..30f07a873b 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -127,10 +127,7 @@ public: LLAppearanceMgr::instance().setOutfitLocked(false); return false; } -// void reset() { mEventTimer.reset(); } bool getStarted() { return isRunning(); } - -// LLTimer& getEventTimer() { return mEventTimer;} }; // support for secondlife:///app/appearance SLapps diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 5fc0ea855e..2041d86fc6 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -65,15 +65,6 @@ void LLToastLifeTimer::setPeriod(F32 period) mPeriod = period; } -/*==========================================================================*| -F32 LLToastLifeTimer::getRemainingTimeF32() -{ - F32 et = mEventTimer.getElapsedTimeF32(); - if (!getStarted() || et > mPeriod) return 0.0f; - return mPeriod - et; -} -|*==========================================================================*/ - //-------------------------------------------------------------------------- LLToast::Params::Params() : can_fade("can_fade", true), diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 460317aaa9..bb5bd981e2 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -57,9 +57,7 @@ public: void restart(); bool getStarted(); void setPeriod(F32 period); -// F32 getRemainingTimeF32(); -// LLTimer& getEventTimer() { return mEventTimer;} private : LLToast* mToast; }; -- cgit v1.2.3 From 86110fd186be29f313d781945ba6cdc500f25b32 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2024 11:14:41 -0400 Subject: Explain the name of the LL::WorkQueue::BackJack class. --- indra/llcommon/workqueue.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index ecc6f27223..1f8cebd336 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -375,6 +375,10 @@ namespace LL * CALLABLE that returns bool, a TimePoint and an interval at which to * relaunch it. As long as the callable continues returning true, BackJack * keeps resubmitting it to the target WorkQueue. + * + * "You go back, Jack, and do it again -- wheel turning' round and round..." + * --Steely Dan, from "Can't Buy a Thrill" (1972) + * https://www.youtube.com/watch?v=yCgHTmv4YU8 */ // Why is BackJack a class and not a lambda? Because, unlike a lambda, a // class method gets its own 'this' pointer -- which we need to resubmit -- cgit v1.2.3 From d61831cabb8c63677e3684c8ba12b24b66923aa9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2024 11:17:48 -0400 Subject: Don't check if printf(format) arg is a string. --- indra/newview/scripts/lua/printf.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/scripts/lua/printf.lua b/indra/newview/scripts/lua/printf.lua index 584cd4f391..e84b2024df 100644 --- a/indra/newview/scripts/lua/printf.lua +++ b/indra/newview/scripts/lua/printf.lua @@ -2,7 +2,7 @@ local inspect = require 'inspect' -local function printf(...) +local function printf(format, ...) -- string.format() only handles numbers and strings. -- Convert anything else to string using the inspect module. local args = {} @@ -13,7 +13,7 @@ local function printf(...) table.insert(args, inspect(arg)) end end - print(string.format(table.unpack(args))) + print(string.format(format, table.unpack(args))) end return printf -- cgit v1.2.3 From e352192045cfe23a681dcaba71d94311f42e230f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2024 11:19:58 -0400 Subject: Add a bit more dbg() conditional diagnostic output. --- indra/newview/scripts/lua/fiber.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/scripts/lua/fiber.lua b/indra/newview/scripts/lua/fiber.lua index 9057e6c890..cae27b936b 100644 --- a/indra/newview/scripts/lua/fiber.lua +++ b/indra/newview/scripts/lua/fiber.lua @@ -17,8 +17,8 @@ -- or with an error). local printf = require 'printf' --- local dbg = printf local function dbg(...) end +-- local dbg = printf local coro = require 'coro' local fiber = {} @@ -303,6 +303,8 @@ function fiber.yield() end -- We're ready! Just return to caller. In this situation we don't care -- whether there are other ready fibers. + dbg('fiber.yield() returning to %s (%sothers are ready)', + fiber.get_name(), ((not others) and "no " or "")) end -- Run fibers until all but main have terminated: return nil. -- cgit v1.2.3 From c59f8bc59ad958d169a7626739b2b81439180537 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2024 11:35:30 -0400 Subject: Add leap.eventstream() and cancelreq() functions. leap.eventstream() is used when we expect the viewer's LLEventAPI to send an immediate first response with the reqid from the request, followed by some number of subsequent responses bearing the same reqid. The difference between eventstream() and generate() is that generate() expects the caller to request each such response, whereas eventstream calls the caller's callback with each response. cancelreq() is for canceling the background fiber launched by eventstream() before the callback tells it to quit. Make WaitFor:close() remove the object from the waitfors list; similarly, make WaitForReqid:close() remove the object from the pending list. For this reason, cleanup() must iterate over a copy of each of the pending and waitfors lists. Instead of unregisterWaitFor() manually searching the waitfors list, use table.find(). --- indra/newview/scripts/lua/leap.lua | 106 ++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index cfb7377523..69cedb4c9e 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -40,6 +40,7 @@ local fiber = require('fiber') local ErrorQueue = require('ErrorQueue') +local inspect = require('inspect') local function dbg(...) end -- local dbg = require('printf') @@ -74,7 +75,7 @@ local reply, command = LL.get_event_pumps() -- pending is NOT a weak table because the caller of request() or generate() -- never sees the WaitForReqid object. pending holds the only reference, so -- it should NOT be garbage-collected. -pending = {} +local pending = {} -- Our consumer will instantiate some number of WaitFor subclass objects. -- As these are traversed in descending priority order, we must keep -- them in a list. @@ -82,7 +83,7 @@ pending = {} -- to it. Once the consuming script drops the reference, allow Lua to -- garbage-collect the WaitFor despite its entry in waitfors. local weak_values = {__mode='v'} -waitfors = setmetatable({}, weak_values) +local waitfors = setmetatable({}, weak_values) -- It has been suggested that we should use UUIDs as ["reqid"] values, -- since UUIDs are guaranteed unique. However, as the "namespace" for -- ["reqid"] values is our very own reply pump, we can get away with @@ -131,7 +132,7 @@ local function requestSetup(pump, data) local waitfor = leap.WaitForReqid:new(reqid) pending[reqid] = waitfor -- Pass reqid to send() to stamp it into (a copy of) the request data. - dbg('requestSetup(%s, %s)', pump, data) + dbg('requestSetup(%s, %s) storing %s', pump, data, waitfor.name) leap.send(pump, data, reqid) return reqid, waitfor end @@ -177,7 +178,7 @@ end -- -- If you pass checklast=, each response event is -- passed to that callable (after the yield). When the callable returns --- True, the generator terminates in the usual way. +-- true, the generator terminates in the usual way. -- -- See request() remarks about ["reqid"]. function leap.generate(pump, data, checklast) @@ -203,12 +204,80 @@ function leap.generate(pump, data, checklast) end end +-- Send the specified request LLSD, expecting an immediate reply followed by +-- an arbitrary number of subsequent replies with the same reqid. Block the +-- calling coroutine until the first (immediate) reply, but launch a separate +-- fiber on which to call the passed callback with later replies. +-- +-- Once the callback returns true, the background fiber terminates. +function leap.eventstream(pump, data, callback) + local reqid, waitfor = requestSetup(pump, data) + local response = waitfor:wait() + if response.error then + -- clean up our WaitForReqid + waitfor:close() + error(response.error) + end + -- No error, so far so good: + -- call the callback with the first response just in case + local ok, done = pcall(callback, response) + if not ok then + -- clean up our WaitForReqid + waitfor:close() + error(done) + end + if done then + return response + end + -- callback didn't throw an error, and didn't say stop, + -- so set up to handle subsequent events + -- TODO: distinguish "daemon" fibers that can be terminated even if waiting + fiber.launch( + pump, + function () + local ok, done + repeat + event = waitfor:wait() + if not event then + -- wait() returns nil once the queue is closed (e.g. cancelreq()) + ok, done = true, true + else + ok, done = pcall(callback, event) + end + -- not ok means callback threw an error (caught as 'done') + -- done means callback succeeded but wants to stop + until (not ok) or done + -- once we break this loop, clean up our WaitForReqid + waitfor:close() + if not ok then + -- can't reflect the error back to our caller + LL.print_warning(fiber.get_name() .. ': ' .. done) + end + end) + return response +end + +-- we might want to clean up after leap.eventstream() even if the callback has +-- not yet returned true +function leap.cancelreq(reqid) + dbg('cancelreq(%s)', reqid) + local waitfor = pending[reqid] + if waitfor ~= nil then + -- close() removes the pending entry and also closes the queue, + -- breaking the background fiber's wait loop. + dbg('cancelreq(%s) canceling %s', reqid, waitfor.name) + waitfor:close() + end +end + local function cleanup(message) - -- we're done: clean up all pending coroutines - for i, waitfor in pairs(pending) do + -- We're done: clean up all pending coroutines. + -- Iterate over copies of the pending and waitfors tables, since the + -- close() operation modifies the real tables. + for i, waitfor in pairs(table.clone(pending)) do waitfor:close() end - for i, waitfor in pairs(waitfors) do + for i, waitfor in pairs(table.clone(waitfors)) do waitfor:close() end end @@ -223,7 +292,8 @@ local function unsolicited(pump, data) return end end - LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', pump, data)) + LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event', + pump, inspect(data))) end -- Route incoming (pump, data) event to the appropriate waiting coroutine. @@ -231,14 +301,17 @@ local function dispatch(pump, data) local reqid = data['reqid'] -- if the response has no 'reqid', it's not from request() or generate() if reqid == nil then +-- dbg('dispatch() found no reqid; calling unsolicited(%s, %s)', pump, data) return unsolicited(pump, data) end -- have reqid; do we have a WaitForReqid? local waitfor = pending[reqid] if waitfor == nil then +-- dbg('dispatch() found no WaitForReqid(%s); calling unsolicited(%s, %s)', reqid, pump, data) return unsolicited(pump, data) end -- found the right WaitForReqid object, let it handle the event +-- dbg('dispatch() calling %s.handle(%s, %s)', waitfor.name, pump, data) waitfor:handle(pump, data) end @@ -284,11 +357,9 @@ end -- called by WaitFor.disable() local function unregisterWaitFor(waitfor) - for i, w in pairs(waitfors) do - if w == waitfor then - waitfors[i] = nil - break - end + local i = table.find(waitfors, waitfor) + if i ~= nil then + waitfors[i] = nil end end @@ -417,6 +488,7 @@ end -- called by cleanup() at end function leap.WaitFor:close() + self:disable() self._queue:close() end @@ -437,6 +509,8 @@ function leap.WaitForReqid:new(reqid) setmetatable(obj, self) self.__index = self + obj.reqid = reqid + return obj end @@ -447,4 +521,10 @@ function leap.WaitForReqid:filter(pump, data) return data end +function leap.WaitForReqid:close() + -- remove this entry from pending table + pending[self.reqid] = nil + self._queue:close() +end + return leap -- cgit v1.2.3 From 894dd1937511df08fa57c5e586d40a7778473dae Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2024 17:02:25 -0400 Subject: Tweak for current Lua dbg() convention. --- indra/newview/scripts/lua/ErrorQueue.lua | 2 +- indra/newview/scripts/lua/WaitQueue.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/scripts/lua/ErrorQueue.lua b/indra/newview/scripts/lua/ErrorQueue.lua index 6ed1c10d5c..13e4e92941 100644 --- a/indra/newview/scripts/lua/ErrorQueue.lua +++ b/indra/newview/scripts/lua/ErrorQueue.lua @@ -3,8 +3,8 @@ -- raise that error. local WaitQueue = require('WaitQueue') --- local dbg = require('printf') local function dbg(...) end +-- local dbg = require('printf') local ErrorQueue = WaitQueue:new() diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index ad4fdecf43..6bcb9d62c2 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -5,8 +5,8 @@ local fiber = require('fiber') local Queue = require('Queue') --- local dbg = require('printf') local function dbg(...) end +-- local dbg = require('printf') local WaitQueue = Queue:new() -- cgit v1.2.3 From de719553fddc381e274d8bff218ab4e3f6691945 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2024 17:15:06 -0400 Subject: Add timers.lua API module and test_timers.lua test program. Since timers presents a timers.Timer Lua class supporting queries and cancellation, make TimersListener::scheduleAfter() and scheduleEvery() respond immediately so the newly constructed Timer object has the reqid necessary to perform those subsequent operations. This requires that Lua invocations of these operations avoid calling the caller's callback with that initial response. Reinvent leap.generate() to return a Lua object supporting next() and done() methods. A plain Lua coroutine that (indirectly) calls fiber.wait() confuses the fiber scheduler, so avoid implementing generate() as a Lua coroutine. Add a bit more leap.lua diagnostic output. --- indra/llcommon/llcallbacklist.cpp | 14 +++-- indra/newview/scripts/lua/leap.lua | 59 ++++++++++------- indra/newview/scripts/lua/test_timers.lua | 39 ++++++++++++ indra/newview/scripts/lua/timers.lua | 101 ++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+), 26 deletions(-) create mode 100644 indra/newview/scripts/lua/test_timers.lua create mode 100644 indra/newview/scripts/lua/timers.lua diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 59ff8d3759..9f324b2fe9 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -410,11 +410,14 @@ private: void TimersListener::scheduleAfter(const LLSD& params) { + // Timer creation functions respond immediately with the reqid of the + // created timer, as well as later when the timer fires. That lets the + // requester invoke cancel, isRunning or timeUntilCall. + Response response(LLSD(), params); LLSD::Real after{ params["after"] }; if (after < MINTIMER) { - sendReply(llsd::map("error", stringize("after must be at least ", MINTIMER)), params); - return; + return response.error(stringize("after must be at least ", MINTIMER)); } mHandles.emplace( @@ -432,11 +435,14 @@ void TimersListener::scheduleAfter(const LLSD& params) void TimersListener::scheduleEvery(const LLSD& params) { + // Timer creation functions respond immediately with the reqid of the + // created timer, as well as later when the timer fires. That lets the + // requester invoke cancel, isRunning or timeUntilCall. + Response response(LLSD(), params); LLSD::Real every{ params["every"] }; if (every < MINTIMER) { - sendReply(llsd::map("error", stringize("every must be at least ", MINTIMER)), params); - return; + return response.error(stringize("every must be at least ", MINTIMER)); } mHandles.emplace( diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 69cedb4c9e..8caae24e94 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -172,36 +172,45 @@ function leap.request(pump, data) end -- Send the specified request LLSD, expecting an arbitrary number of replies. --- Each one is yielded on receipt. If you omit checklast, this is an infinite --- generator; it's up to the caller to recognize when the last reply has been --- received, and stop resuming for more. --- --- If you pass checklast=, each response event is --- passed to that callable (after the yield). When the callable returns --- true, the generator terminates in the usual way. +-- Each one is returned on request. +-- +-- Usage: +-- sequence = leap.generate(pump, data) +-- repeat +-- response = sequence.next() +-- until last(response) +-- (last() means whatever test the caller wants to perform on response) +-- sequence.done() -- -- See request() remarks about ["reqid"]. +-- +-- Note: this seems like a prime use case for Lua coroutines. But in a script +-- using fibers.lua, a "wild" coroutine confuses the fiber scheduler. If +-- generate() were itself a coroutine, it would call WaitForReqid:wait(), +-- which would yield -- thereby resuming generate() WITHOUT waiting. function leap.generate(pump, data, checklast) -- Invent a new, unique reqid. Arrange to handle incoming events -- bearing that reqid. Stamp the outbound request with that reqid, and -- send it. local reqid, waitfor = requestSetup(pump, data) - local ok, response, resumed_with - repeat - ok, response = pcall(waitfor.wait, waitfor) - if (not ok) or response.error then - break + return { + next = function() + dbg('leap.generate(%s).next() about to wait on %s', reqid, tostring(waitfor)) + local ok, response = pcall(waitfor.wait, waitfor) + dbg('leap.generate(%s).next() got %s: %s', reqid, ok, response) + if not ok then + error(response) + elseif response.error then + error(response.error) + else + return response + end + end, + done = function() + -- cleanup consists of removing our WaitForReqid from pending + pending[reqid] = nil end - -- can resume(false) to terminate generate() and clean up - resumed_with = coroutine.yield(response) - until (checklast and checklast(response)) or (resumed_with == false) - -- If we break the above loop, whether or not due to error, clean up. - pending[reqid] = nil - if not ok then - error(response) - elseif response.error then - error(response.error) - end + } end -- Send the specified request LLSD, expecting an immediate reply followed by @@ -220,7 +229,9 @@ function leap.eventstream(pump, data, callback) end -- No error, so far so good: -- call the callback with the first response just in case + dbg('leap.eventstream(%s): first callback', reqid) local ok, done = pcall(callback, response) + dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) if not ok then -- clean up our WaitForReqid waitfor:close() @@ -236,13 +247,17 @@ function leap.eventstream(pump, data, callback) pump, function () local ok, done + local nth = 1 repeat event = waitfor:wait() if not event then -- wait() returns nil once the queue is closed (e.g. cancelreq()) ok, done = true, true else + nth += 1 + dbg('leap.eventstream(%s): callback %d', reqid, nth) ok, done = pcall(callback, event) + dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done) end -- not ok means callback threw an error (caught as 'done') -- done means callback succeeded but wants to stop diff --git a/indra/newview/scripts/lua/test_timers.lua b/indra/newview/scripts/lua/test_timers.lua new file mode 100644 index 0000000000..53a2dc83f2 --- /dev/null +++ b/indra/newview/scripts/lua/test_timers.lua @@ -0,0 +1,39 @@ +local timers = require 'timers' + +print('t0:new(10)') +start = os.clock() +t0 = timers.Timer:new(10, function() print('t0 fired at', os.clock() - start) end) +print('t0:isRunning(): ', t0:isRunning()) +print('t0:timeUntilCall(): ', t0:timeUntilCall()) +print('t0:cancel(): ', t0:cancel()) +print('t0:isRunning(): ', t0:isRunning()) +print('t0:timeUntilCall(): ', t0:timeUntilCall()) +print('t0:cancel(): ', t0:cancel()) + +print('t1:new(5)') +start = os.clock() +t1 = timers.Timer:new(5, function() print('t1 fired at', os.clock() - start) end) + +print('t2:new(2)') +start = os.clock() +t2 = timers.Timer:new(2) +function t2:tick() + print('t2 fired at', os.clock() - start) +end + +start = os.clock() +timers.Timer:new(5, 'wait') +print(string.format('Timer(5) waited %f seconds', os.clock() - start)) + +start = os.clock() +timers.Timer:new( + 2, + coroutine.wrap(function() + for i = 1,5 do + print('repeat(2) timer fired at ', os.clock() - start) + coroutine.yield(nil) -- keep running + end + print('repeat(2) timer fired last at ', os.clock() - start) + return true -- stop + end), + true) -- iterate diff --git a/indra/newview/scripts/lua/timers.lua b/indra/newview/scripts/lua/timers.lua new file mode 100644 index 0000000000..e0d27a680d --- /dev/null +++ b/indra/newview/scripts/lua/timers.lua @@ -0,0 +1,101 @@ +-- Access to the viewer's time-delay facilities + +local leap = require 'leap' + +local timers = {} + +local function dbg(...) end +-- local dbg = require 'printf' + +timers.Timer = {} + +-- delay: time in seconds until callback +-- callback: 'wait', or function to call when timer fires (self:tick if nil) +-- iterate: if non-nil, call callback repeatedly until it returns non-nil +-- (ignored if 'wait') +function timers.Timer:new(delay, callback, iterate) + local obj = setmetatable({}, self) + self.__index = self + + if callback == 'wait' then + dbg('scheduleAfter(%d):', delay) + sequence = leap.generate('Timers', {op='scheduleAfter', after=delay}) + -- ignore the immediate return + dbg('scheduleAfter(%d) -> %s', delay, + sequence.next()) + -- this call is where we wait for real + dbg('next():') + dbg('next() -> %s', + sequence.next()) + sequence.done() + return + end + + callback = callback or function() obj:tick() end + + local first = true + if iterate then + obj.id = leap.eventstream( + 'Timers', + {op='scheduleEvery', every=delay}, + function (event) + local reqid = event.reqid + if first then + first = false + dbg('timer(%s) first callback', reqid) + -- discard the first (immediate) response: don't call callback + return nil + else + dbg('timer(%s) nth callback', reqid) + return callback(event) + end + end + ).reqid + else + obj.id = leap.eventstream( + 'Timers', + {op='scheduleAfter', after=delay}, + function (event) + -- Arrange to return nil the first time, true the second. This + -- callback is called immediately with the response to + -- 'scheduleAfter', and if we immediately returned true, we'd + -- be done, and the subsequent timer event would be discarded. + if first then + first = false + -- Caller doesn't expect an immediate callback. + return nil + else + callback(event) + -- Since caller doesn't want to iterate, the value + -- returned by the callback is irrelevant: just stop after + -- this one and only call. + return true + end + end + ).reqid + end + + return obj +end + +function timers.Timer:tick() + error('Pass a callback to Timer:new(), or override Timer:tick()') +end + +function timers.Timer:cancel() + local ok = leap.request('Timers', {op='cancel', id=self.id}).ok + leap.cancelreq(self.id) + return ok +end + +function timers.Timer:isRunning() + return leap.request('Timers', {op='isRunning', id=self.id}).running +end + +-- returns (true, seconds left) for a live timer, else (false, 0) +function timers.Timer:timeUntilCall() + local result = leap.request('Timers', {op='timeUntilCall', id=self.id}) + return result.ok, result.remaining +end + +return timers -- cgit v1.2.3 From 47821cf53f89acec4ed6d465e14d7793d2420b41 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 3 Jun 2024 11:48:11 -0400 Subject: Leverage new leap.eventstream() function in Floater.lua. --- indra/newview/scripts/lua/Floater.lua | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/indra/newview/scripts/lua/Floater.lua b/indra/newview/scripts/lua/Floater.lua index 76efd47c43..75696533e4 100644 --- a/indra/newview/scripts/lua/Floater.lua +++ b/indra/newview/scripts/lua/Floater.lua @@ -46,10 +46,18 @@ function Floater:new(path, extra) end function Floater:show() - local event = leap.request('LLFloaterReg', self._command) + -- leap.eventstream() returns the first response, and launches a + -- background fiber to call the passed callback with all subsequent + -- responses. + local event = leap.eventstream( + 'LLFloaterReg', + self._command, + -- handleEvents() returns false when done. + -- eventstream() expects a true return when done. + function(event) return not self:handleEvents(event) end) self._pump = event.command_name - -- we use the returned reqid to claim subsequent unsolicited events - local reqid = event.reqid + -- we might need the returned reqid to cancel the eventstream() fiber + self.reqid = event.reqid -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if -- subclass has a post_build() method. Honor the convention that if @@ -57,22 +65,6 @@ function Floater:show() if not self:handleEvents(event) then return end - - local waitfor = leap.WaitFor:new(-1, self.name) - function waitfor:filter(pump, data) - if data.reqid == reqid then - return data - end - end - - fiber.launch( - self.name, - function () - event = waitfor:wait() - while event and self:handleEvents(event) do - event = waitfor:wait() - end - end) end function Floater:post(action) @@ -125,7 +117,7 @@ function Floater:handleEvents(event_data) -- We check for event() method before recognizing floater_close in case -- the consumer needs to react specially to closing the floater. Now that -- we've checked, recognize it ourselves. Returning false terminates the - -- anonymous fiber function launched by show(). + -- anonymous fiber function launched by leap.eventstream(). if event == _event('floater_close') then LL.print_warning(self.name .. ' closed') return false -- cgit v1.2.3 From 22d5f39796fbe98f3f9c657e35e57a4c6235ca2e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 3 Jun 2024 14:51:33 -0400 Subject: Distinguish TimersListener callers by reply LLEventPump name. The reqid is only distinct within a particular calling script. --- indra/llcommon/llcallbacklist.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 9f324b2fe9..bf7a555140 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -28,6 +28,7 @@ #include "llcallbacklist.h" #include "llexception.h" #include "llsdutil.h" +#include #include // @@ -404,7 +405,16 @@ public: LLSD timeUntilCall(const LLSD& params); private: - using HandleMap = std::unordered_map; + // We use the incoming reqid to distinguish different timers -- but reqid + // by itself is not unique! Each reqid is local to a calling script. + // Distinguish scripts by reply-pump name, then reqid within script. + // "Additional specializations for std::pair and the standard container + // types, as well as utility functions to compose hashes are available in + // boost::hash." + // https://en.cppreference.com/w/cpp/utility/hash + using HandleKey = std::pair; + using HandleMap = std::unordered_map>; HandleMap mHandles; }; @@ -420,15 +430,16 @@ void TimersListener::scheduleAfter(const LLSD& params) return response.error(stringize("after must be at least ", MINTIMER)); } + HandleKey key{ params["reply"], params["reqid"] }; mHandles.emplace( - params["reqid"], + key, Timers::instance().scheduleAfter( - [this, params] + [this, params, key] { // we don't need any content save for the "reqid" sendReply({}, params); // ditch mHandles entry - mHandles.erase(params["reqid"]); + mHandles.erase(key); }, after)); } @@ -446,7 +457,7 @@ void TimersListener::scheduleEvery(const LLSD& params) } mHandles.emplace( - params["reqid"], + HandleKey{ params["reply"], params["reqid"] }, Timers::instance().scheduleEvery( [params, i=0]() mutable { @@ -460,7 +471,7 @@ void TimersListener::scheduleEvery(const LLSD& params) LLSD TimersListener::cancel(const LLSD& params) { - auto found{ mHandles.find(params["id"]) }; + auto found{ mHandles.find({params["reply"], params["id"]}) }; bool ok = false; if (found != mHandles.end()) { @@ -473,7 +484,7 @@ LLSD TimersListener::cancel(const LLSD& params) LLSD TimersListener::isRunning(const LLSD& params) { - auto found{ mHandles.find(params["id"]) }; + auto found{ mHandles.find({params["reply"], params["id"]}) }; bool running = false; if (found != mHandles.end()) { @@ -484,7 +495,7 @@ LLSD TimersListener::isRunning(const LLSD& params) LLSD TimersListener::timeUntilCall(const LLSD& params) { - auto found{ mHandles.find(params["id"]) }; + auto found{ mHandles.find({params["reply"], params["id"]}) }; bool ok = false; LLSD::Real remaining = 0; if (found != mHandles.end()) -- cgit v1.2.3 From ce9886e3d374df3017eeaeeb9e30f28343712896 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 3 Jun 2024 16:50:22 -0400 Subject: Allow consumer code to query or adjust the per-tick timeslice. --- indra/llcommon/llcallbacklist.cpp | 22 +++++++++++++++++++++- indra/llcommon/llcallbacklist.h | 10 +++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index bf7a555140..015475a903 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -26,9 +26,11 @@ #include "lazyeventapi.h" #include "llcallbacklist.h" +#include "llerror.h" #include "llexception.h" #include "llsdutil.h" #include +#include #include // @@ -272,6 +274,24 @@ bool Timers::cancel(const handle_t& timer) return true; } +void Timers::setTimeslice(F32 timeslice) +{ + if (timeslice < MINIMUM_TIMESLICE) + { + // use stringize() so setprecision() affects only the temporary + // ostream, not the common logging ostream + LL_WARNS("Timers") << "LL::Timers::setTimeslice(" + << stringize(std::setprecision(4), timeslice) + << ") less than " + << stringize(std::setprecision(4), MINIMUM_TIMESLICE) + << ", ignoring" << LL_ENDL; + } + else + { + mTimeslice = timeslice; + } +} + // RAII class to set specified variable to specified value // only for the duration of containing scope template @@ -305,7 +325,7 @@ bool Timers::tick() // sharing this thread with everything else, and there's a risk we might // starve it if we have a sequence of tasks that take nontrivial time. auto now{ LLDate::now().secondsSinceEpoch() }; - auto cutoff{ now + TIMESLICE }; + auto cutoff{ now + mTimeslice }; // Capture tasks we've processed but that want to be rescheduled. // Defer rescheduling them immediately to avoid getting stuck looping over diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index b245b3db94..fb4696188a 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -147,7 +147,11 @@ class Timers: public LLSingleton public: // If tasks that come ready during a given tick() take longer than this, // defer any subsequent ready tasks to a future tick() call. - static constexpr F32 TIMESLICE{ 0.005f }; + static constexpr F32 DEFAULT_TIMESLICE{ 0.005f }; + // Setting timeslice to be less than MINIMUM_TIMESLICE could lock up + // Timers processing, causing it to believe it's exceeded the allowable + // time every tick before processing ANY queue items. + static constexpr F32 MINIMUM_TIMESLICE{ 0.001f }; class handle_t { @@ -182,6 +186,9 @@ public: // cancel again. bool cancel(handle_t& timer); + F32 getTimeslice() const { return mTimeslice; } + void setTimeslice(F32 timeslice); + // Store a handle_t returned by scheduleAt(), scheduleAfter() or // scheduleEvery() in a temp_handle_t to cancel() automatically on // destruction of the temp_handle_t. @@ -278,6 +285,7 @@ private: token_t mToken{ 0 }; // While mQueue is non-empty, register for regular callbacks. LLCallbackList::temp_handle_t mLive; + F32 mTimeslice{ DEFAULT_TIMESLICE }; }; } // namespace LL -- cgit v1.2.3 From c3ccf00e91ff61bd3ea6c6f7ffb3709442e2270a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 3 Jun 2024 17:02:19 -0400 Subject: Fix a small typo --- indra/llcommon/workqueue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index 1f8cebd336..0581f85bfa 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -376,7 +376,7 @@ namespace LL * relaunch it. As long as the callable continues returning true, BackJack * keeps resubmitting it to the target WorkQueue. * - * "You go back, Jack, and do it again -- wheel turning' round and round..." + * "You go back, Jack, and do it again -- wheel turnin' round and round..." * --Steely Dan, from "Can't Buy a Thrill" (1972) * https://www.youtube.com/watch?v=yCgHTmv4YU8 */ -- cgit v1.2.3 From 9e6cf32add0a857b4e28c638bd378a8d3f70fcdb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 4 Jun 2024 09:52:55 -0400 Subject: Comment the intent of test_timers.lua so the user need not reverse-engineer the code to figure out the output. --- indra/newview/scripts/lua/test_timers.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/indra/newview/scripts/lua/test_timers.lua b/indra/newview/scripts/lua/test_timers.lua index 53a2dc83f2..ed0de070f7 100644 --- a/indra/newview/scripts/lua/test_timers.lua +++ b/indra/newview/scripts/lua/test_timers.lua @@ -1,5 +1,11 @@ local timers = require 'timers' +-- This t0 is constructed for 10 seconds, but its purpose is to exercise the +-- query and cancel methods. It would print "t0 fired at..." if it fired, but +-- it doesn't, so you don't see that message. Instead you see that isRunning() +-- is true, that timeUntilCall() is (true, close to 10), that cancel() returns +-- true. After that, isRunning() is false, timeUntilCall() returns (false, 0), +-- and a second cancel() returns false. print('t0:new(10)') start = os.clock() t0 = timers.Timer:new(10, function() print('t0 fired at', os.clock() - start) end) @@ -10,10 +16,15 @@ print('t0:isRunning(): ', t0:isRunning()) print('t0:timeUntilCall(): ', t0:timeUntilCall()) print('t0:cancel(): ', t0:cancel()) +-- t1 is supposed to fire after 5 seconds, but it doesn't wait, so you see the +-- t2 messages immediately after. print('t1:new(5)') start = os.clock() t1 = timers.Timer:new(5, function() print('t1 fired at', os.clock() - start) end) +-- t2 illustrates that instead of passing a callback to new(), you can +-- override the timer instance's tick() method. But t2 doesn't wait either, so +-- you see the Timer(5) message immediately. print('t2:new(2)') start = os.clock() t2 = timers.Timer:new(2) @@ -21,10 +32,23 @@ function t2:tick() print('t2 fired at', os.clock() - start) end +-- This anonymous timer blocks the calling fiber for 5 seconds. Other fibers +-- are free to run during that time, so you see the t2 callback message and +-- then the t1 callback message before the Timer(5) completion message. +print('Timer(5) waiting') start = os.clock() timers.Timer:new(5, 'wait') print(string.format('Timer(5) waited %f seconds', os.clock() - start)) +-- This test demonstrates a repeating timer. It also shows that you can (but +-- need not) use a coroutine as the timer's callback function: unlike Python, +-- Lua doesn't disinguish between yield() and return. A coroutine wrapped with +-- coroutine.wrap() looks to Lua just like any other function that you can +-- call repeatedly and get a result each time. We use that to count the +-- callback calls and stop after a certain number. Of course that could also +-- be arranged in a plain function by incrementing a script-scope counter, but +-- it's worth knowing that a coroutine timer callback can be used to manage +-- more complex control flows. start = os.clock() timers.Timer:new( 2, -- cgit v1.2.3