diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py index 17bce6f43445792c586a0644880e59ba955b1c8a..fff78ecbe330e1ecabcde00276c154ae37407eff 100644 --- a/indra/cmake/run_build_test.py +++ b/indra/cmake/run_build_test.py @@ -1,111 +1,111 @@ -#!/usr/bin/python -"""\ -@file run_build_test.py -@author Nat Goodspeed -@date 2009-09-03 -@brief Helper script to allow CMake to run some command after setting - environment variables. - -CMake has commands to run an external program. But remember that each CMake -command must be backed by multiple build-system implementations. Unfortunately -it seems CMake can't promise that every target build system can set specified -environment variables before running the external program of interest. - -This helper script is a workaround. It simply sets the requested environment -variables and then executes the program specified on the rest of its command -line. - -Example: - -python run_build_test.py -DFOO=bar myprog somearg otherarg - -sets environment variable FOO=bar, then runs: -myprog somearg otherarg - -$LicenseInfo:firstyear=2009&license=internal$ -Copyright (c) 2009, Linden Research, Inc. -$/LicenseInfo$ -""" - -import os -import sys -import subprocess - -def main(command, libpath=[], vars={}): - """Pass: - command is a sequence (e.g. a list) of strings. The first item in the list - must be the command name, the rest are its arguments. - - libpath is a sequence of directory pathnames. These will be appended to - the platform-specific dynamic library search path environment variable. - - vars is a dict of arbitrary (var, value) pairs to be added to the - environment before running 'command'. - - This function runs the specified command, waits for it to terminate and - returns its return code. This will be negative if the command terminated - with a signal, else it will be the process's specified exit code. - """ - # Handle platform-dependent libpath first. - if sys.platform == "win32": - lpvars = ["PATH"] - elif sys.platform == "darwin": - lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"] - elif sys.platform.startswith("linux"): - lpvars = ["LD_LIBRARY_PATH"] - else: - # No idea what the right pathname might be! But only crump if this - # feature is requested. - if libpath: - raise NotImplemented("run_build_test: unknown platform %s" % sys.platform) - lpvars = [] - for var in lpvars: - # Split the existing path. Bear in mind that the variable in question - # might not exist; instead of KeyError, just use an empty string. - dirs = os.environ.get(var, "").split(os.pathsep) - # Append the sequence in libpath -## print "%s += %r" % (var, libpath) - dirs.extend(libpath) - # Now rebuild the path string. This way we use a minimum of separators - # -- and we avoid adding a pointless separator when libpath is empty. - os.environ[var] = os.pathsep.join(dirs) - # Now handle arbitrary environment variables. The tricky part is ensuring - # that all the keys and values we try to pass are actually strings. -## if vars: -## print "Setting:" -## for key, value in vars.iteritems(): -## print "%s=%s" % (key, value) - os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()])) - # Run the child process. -## print "Running: %s" % " ".join(command) - return subprocess.call(command) - -if __name__ == "__main__": - from optparse import OptionParser - parser = OptionParser(usage="usage: %prog [options] command args...") - # We want optparse support for the options we ourselves handle -- but we - # DO NOT want it looking at options for the executable we intend to run, - # rejecting them as invalid because we don't define them. So configure the - # parser to stop looking for options as soon as it sees the first - # positional argument (traditional Unix syntax). - parser.disable_interspersed_args() - parser.add_option("-D", "--define", dest="vars", default=[], action="append", - metavar="VAR=value", - help="Add VAR=value to the env variables defined") - parser.add_option("-l", "--libpath", dest="libpath", default=[], action="append", - metavar="DIR", - help="Add DIR to the platform-dependent DLL search path") - opts, args = parser.parse_args() - # What we have in opts.vars is a list of strings of the form "VAR=value" - # or possibly just "VAR". What we want is a dict. We can build that dict by - # constructing a list of ["VAR", "value"] pairs -- so split each - # "VAR=value" string on the '=' sign (but only once, in case we have - # "VAR=some=user=string"). To handle the case of just "VAR", append "" to - # the list returned by split(), then slice off anything after the pair we - # want. - rc = main(command=args, libpath=opts.libpath, - vars=dict([(pair.split('=', 1) + [""])[:2] for pair in opts.vars])) - if rc not in (None, 0): - print >>sys.stderr, "Failure running: %s" % " ".join(args) - print >>sys.stderr, "Error: %s" % rc - sys.exit((rc < 0) and 255 or rc) +#!/usr/bin/python +"""\ +@file run_build_test.py +@author Nat Goodspeed +@date 2009-09-03 +@brief Helper script to allow CMake to run some command after setting + environment variables. + +CMake has commands to run an external program. But remember that each CMake +command must be backed by multiple build-system implementations. Unfortunately +it seems CMake can't promise that every target build system can set specified +environment variables before running the external program of interest. + +This helper script is a workaround. It simply sets the requested environment +variables and then executes the program specified on the rest of its command +line. + +Example: + +python run_build_test.py -DFOO=bar myprog somearg otherarg + +sets environment variable FOO=bar, then runs: +myprog somearg otherarg + +$LicenseInfo:firstyear=2009&license=internal$ +Copyright (c) 2009, Linden Research, Inc. +$/LicenseInfo$ +""" + +import os +import sys +import subprocess + +def main(command, libpath=[], vars={}): + """Pass: + command is a sequence (e.g. a list) of strings. The first item in the list + must be the command name, the rest are its arguments. + + libpath is a sequence of directory pathnames. These will be appended to + the platform-specific dynamic library search path environment variable. + + vars is a dict of arbitrary (var, value) pairs to be added to the + environment before running 'command'. + + This function runs the specified command, waits for it to terminate and + returns its return code. This will be negative if the command terminated + with a signal, else it will be the process's specified exit code. + """ + # Handle platform-dependent libpath first. + if sys.platform == "win32": + lpvars = ["PATH"] + elif sys.platform == "darwin": + lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"] + elif sys.platform.startswith("linux"): + lpvars = ["LD_LIBRARY_PATH"] + else: + # No idea what the right pathname might be! But only crump if this + # feature is requested. + if libpath: + raise NotImplemented("run_build_test: unknown platform %s" % sys.platform) + lpvars = [] + for var in lpvars: + # Split the existing path. Bear in mind that the variable in question + # might not exist; instead of KeyError, just use an empty string. + dirs = os.environ.get(var, "").split(os.pathsep) + # Append the sequence in libpath +## print "%s += %r" % (var, libpath) + dirs.extend(libpath) + # Now rebuild the path string. This way we use a minimum of separators + # -- and we avoid adding a pointless separator when libpath is empty. + os.environ[var] = os.pathsep.join(dirs) + # Now handle arbitrary environment variables. The tricky part is ensuring + # that all the keys and values we try to pass are actually strings. +## if vars: +## print "Setting:" +## for key, value in vars.iteritems(): +## print "%s=%s" % (key, value) + os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()])) + # Run the child process. +## print "Running: %s" % " ".join(command) + return subprocess.call(command) + +if __name__ == "__main__": + from optparse import OptionParser + parser = OptionParser(usage="usage: %prog [options] command args...") + # We want optparse support for the options we ourselves handle -- but we + # DO NOT want it looking at options for the executable we intend to run, + # rejecting them as invalid because we don't define them. So configure the + # parser to stop looking for options as soon as it sees the first + # positional argument (traditional Unix syntax). + parser.disable_interspersed_args() + parser.add_option("-D", "--define", dest="vars", default=[], action="append", + metavar="VAR=value", + help="Add VAR=value to the env variables defined") + parser.add_option("-l", "--libpath", dest="libpath", default=[], action="append", + metavar="DIR", + help="Add DIR to the platform-dependent DLL search path") + opts, args = parser.parse_args() + # What we have in opts.vars is a list of strings of the form "VAR=value" + # or possibly just "VAR". What we want is a dict. We can build that dict by + # constructing a list of ["VAR", "value"] pairs -- so split each + # "VAR=value" string on the '=' sign (but only once, in case we have + # "VAR=some=user=string"). To handle the case of just "VAR", append "" to + # the list returned by split(), then slice off anything after the pair we + # want. + rc = main(command=args, libpath=opts.libpath, + vars=dict([(pair.split('=', 1) + [""])[:2] for pair in opts.vars])) + if rc not in (None, 0): + print >>sys.stderr, "Failure running: %s" % " ".join(args) + print >>sys.stderr, "Error: %s" % rc + sys.exit((rc < 0) and 255 or rc) diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h index 0d6f18c5d47a80cc06499df7b2e50eddd0ce0ffd..50129b4526d7d2bb4ac4120cedc352fda79cfc06 100644 --- a/indra/llcommon/llallocator.h +++ b/indra/llcommon/llallocator.h @@ -1,63 +1,63 @@ -/** - * @file llallocator.h - * @brief Declaration of the LLAllocator class. - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLALLOCATOR_H -#define LL_LLALLOCATOR_H - -#include <string> - -#include "llmemtype.h" -#include "llallocator_heap_profile.h" - -class LL_COMMON_API LLAllocator { - friend class LLMemoryView; - friend class LLMemType; - -private: - static void pushMemType(S32 type); - static S32 popMemType(); - -public: - void setProfilingEnabled(bool should_enable); - - static bool isProfiling(); - - LLAllocatorHeapProfile const & getProfile(); - -private: - std::string getRawProfile(); - -private: - LLAllocatorHeapProfile mProf; -}; - -#endif // LL_LLALLOCATOR_H +/** + * @file llallocator.h + * @brief Declaration of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_H +#define LL_LLALLOCATOR_H + +#include <string> + +#include "llmemtype.h" +#include "llallocator_heap_profile.h" + +class LL_COMMON_API LLAllocator { + friend class LLMemoryView; + friend class LLMemType; + +private: + static void pushMemType(S32 type); + static S32 popMemType(); + +public: + void setProfilingEnabled(bool should_enable); + + static bool isProfiling(); + + LLAllocatorHeapProfile const & getProfile(); + +private: + std::string getRawProfile(); + +private: + LLAllocatorHeapProfile mProf; +}; + +#endif // LL_LLALLOCATOR_H diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 0898aeec470e26e02717b8dddf03352f6e8c2373..a1fcd2cf8ddd0814d7c374da579f4d1285ba0882 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -1,259 +1,259 @@ -/** - * @file llapr.h - * @author Phoenix - * @date 2004-11-28 - * @brief Helper functions for using the apache portable runtime library. - * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLAPR_H -#define LL_LLAPR_H - -#if LL_LINUX || LL_SOLARIS -#include <sys/param.h> // Need PATH_MAX in APR headers... -#endif - -#include <boost/noncopyable.hpp> - -#include "apr_thread_proc.h" -#include "apr_thread_mutex.h" -#include "apr_getopt.h" -#include "apr_signal.h" -#include "apr_atomic.h" -#include "llstring.h" - -extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; -extern apr_thread_mutex_t* gCallStacksLogMutexp; - -/** - * @brief initialize the common apr constructs -- apr itself, the - * global pool, and a mutex. - */ -void LL_COMMON_API ll_init_apr(); - -/** - * @brief Cleanup those common apr constructs. - */ -void LL_COMMON_API ll_cleanup_apr(); - -// -//LL apr_pool -//manage apr_pool_t, destroy allocated apr_pool in the destruction function. -// -class LL_COMMON_API LLAPRPool -{ -public: - LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; - ~LLAPRPool() ; - - apr_pool_t* getAPRPool() ; - apr_status_t getStatus() {return mStatus ; } - -protected: - void releaseAPRPool() ; - void createAPRPool() ; - -protected: - apr_pool_t* mPool ; //pointing to an apr_pool - apr_pool_t* mParent ; //parent pool - apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. - apr_status_t mStatus ; //status when creating the pool - BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. -}; - -// -//volatile LL apr_pool -//which clears memory automatically. -//so it can not hold static data or data after memory is cleared -// -class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool -{ -public: - LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); - ~LLVolatileAPRPool(){} - - apr_pool_t* getVolatileAPRPool() ; - - void clearVolatileAPRPool() ; - - BOOL isFull() ; - BOOL isEmpty() {return !mNumActiveRef ;} -private: - S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. - S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. -} ; - -/** - * @class LLScopedLock - * @brief Small class to help lock and unlock mutexes. - * - * This class is used to have a stack level lock once you already have - * an apr mutex handy. The constructor handles the lock, and the - * destructor handles the unlock. Instances of this class are - * <b>not</b> thread safe. - */ -class LL_COMMON_API LLScopedLock : private boost::noncopyable -{ -public: - /** - * @brief Constructor which accepts a mutex, and locks it. - * - * @param mutex An allocated APR mutex. If you pass in NULL, - * this wrapper will not lock. - */ - LLScopedLock(apr_thread_mutex_t* mutex); - - /** - * @brief Destructor which unlocks the mutex if still locked. - */ - ~LLScopedLock(); - - /** - * @brief Check lock. - */ - bool isLocked() const { return mLocked; } - - /** - * @brief This method unlocks the mutex. - */ - void unlock(); - -protected: - bool mLocked; - apr_thread_mutex_t* mMutex; -}; - -template <typename Type> class LLAtomic32 -{ -public: - LLAtomic32<Type>() {}; - LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); }; - ~LLAtomic32<Type>() {}; - - operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); } - Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); } - void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); } - void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); } - Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++ - Type operator --(int) { return apr_atomic_dec32(&mData); } // Type-- - -private: - apr_uint32_t mData; -}; - -typedef LLAtomic32<U32> LLAtomicU32; -typedef LLAtomic32<S32> LLAtomicS32; - -// File IO convenience functions. -// Returns NULL if the file fails to openm sets *sizep to file size of not NULL -// abbreviated flags -#define LL_APR_R (APR_READ) // "r" -#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w" -#define LL_APR_RB (APR_READ|APR_BINARY) // "rb" -#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" -#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" -#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" - -// -//apr_file manager -//which: 1)only keeps one file open; -// 2)closes the open file in the destruction function -// 3)informs the apr_pool to clean the memory when the file is closed. -//Note: please close an open file at the earliest convenience. -// especially do not put some time-costly operations between open() and close(). -// otherwise it might lock the APRFilePool. -//there are two different apr_pools the APRFile can use: -// 1, a temperary pool passed to an APRFile function, which is used within this function and only once. -// 2, a global pool. -// -class LL_COMMON_API LLAPRFile -{ -private: - apr_file_t* mFile ; - LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. - -public: - LLAPRFile() ; - ~LLAPRFile() ; - - apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL); - apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL); - apr_status_t close() ; - - // Returns actual offset, -1 if seek fails - S32 seek(apr_seek_where_t where, S32 offset); - apr_status_t eof() { return apr_file_eof(mFile);} - - // Returns bytes read/written, 0 if read/write fails: - S32 read(void* buf, S32 nbytes); - S32 write(const void* buf, S32 nbytes); - - apr_file_t* getFileHandle() {return mFile;} - -private: - apr_pool_t* getAPRFilePool(apr_pool_t* pool) ; - -// -//******************************************************************************************************************************* -//static components -// -public: - static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. - -private: - static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags); - static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ; - static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); -public: - // returns false if failure: - static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); - static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); - static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - - // Returns bytes read/written, 0 if read/write fails: - static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); -//******************************************************************************************************************************* -}; - -/** - * @brief Function which approprately logs error or remains quiet on - * APR_SUCCESS. - * @return Returns <code>true</code> if status is an error condition. - */ -bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); - -void LL_COMMON_API ll_apr_assert_status(apr_status_t status); - -extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool - -#endif // LL_LLAPR_H +/** + * @file llapr.h + * @author Phoenix + * @date 2004-11-28 + * @brief Helper functions for using the apache portable runtime library. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAPR_H +#define LL_LLAPR_H + +#if LL_LINUX || LL_SOLARIS +#include <sys/param.h> // Need PATH_MAX in APR headers... +#endif + +#include <boost/noncopyable.hpp> + +#include "apr_thread_proc.h" +#include "apr_thread_mutex.h" +#include "apr_getopt.h" +#include "apr_signal.h" +#include "apr_atomic.h" +#include "llstring.h" + +extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; +extern apr_thread_mutex_t* gCallStacksLogMutexp; + +/** + * @brief initialize the common apr constructs -- apr itself, the + * global pool, and a mutex. + */ +void LL_COMMON_API ll_init_apr(); + +/** + * @brief Cleanup those common apr constructs. + */ +void LL_COMMON_API ll_cleanup_apr(); + +// +//LL apr_pool +//manage apr_pool_t, destroy allocated apr_pool in the destruction function. +// +class LL_COMMON_API LLAPRPool +{ +public: + LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; + ~LLAPRPool() ; + + apr_pool_t* getAPRPool() ; + apr_status_t getStatus() {return mStatus ; } + +protected: + void releaseAPRPool() ; + void createAPRPool() ; + +protected: + apr_pool_t* mPool ; //pointing to an apr_pool + apr_pool_t* mParent ; //parent pool + apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. + apr_status_t mStatus ; //status when creating the pool + BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. +}; + +// +//volatile LL apr_pool +//which clears memory automatically. +//so it can not hold static data or data after memory is cleared +// +class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool +{ +public: + LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); + ~LLVolatileAPRPool(){} + + apr_pool_t* getVolatileAPRPool() ; + + void clearVolatileAPRPool() ; + + BOOL isFull() ; + BOOL isEmpty() {return !mNumActiveRef ;} +private: + S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. + S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. +} ; + +/** + * @class LLScopedLock + * @brief Small class to help lock and unlock mutexes. + * + * This class is used to have a stack level lock once you already have + * an apr mutex handy. The constructor handles the lock, and the + * destructor handles the unlock. Instances of this class are + * <b>not</b> thread safe. + */ +class LL_COMMON_API LLScopedLock : private boost::noncopyable +{ +public: + /** + * @brief Constructor which accepts a mutex, and locks it. + * + * @param mutex An allocated APR mutex. If you pass in NULL, + * this wrapper will not lock. + */ + LLScopedLock(apr_thread_mutex_t* mutex); + + /** + * @brief Destructor which unlocks the mutex if still locked. + */ + ~LLScopedLock(); + + /** + * @brief Check lock. + */ + bool isLocked() const { return mLocked; } + + /** + * @brief This method unlocks the mutex. + */ + void unlock(); + +protected: + bool mLocked; + apr_thread_mutex_t* mMutex; +}; + +template <typename Type> class LLAtomic32 +{ +public: + LLAtomic32<Type>() {}; + LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); }; + ~LLAtomic32<Type>() {}; + + operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); } + Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); } + void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); } + void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); } + Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++ + Type operator --(int) { return apr_atomic_dec32(&mData); } // Type-- + +private: + apr_uint32_t mData; +}; + +typedef LLAtomic32<U32> LLAtomicU32; +typedef LLAtomic32<S32> LLAtomicS32; + +// File IO convenience functions. +// Returns NULL if the file fails to openm sets *sizep to file size of not NULL +// abbreviated flags +#define LL_APR_R (APR_READ) // "r" +#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w" +#define LL_APR_RB (APR_READ|APR_BINARY) // "rb" +#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" +#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" +#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" + +// +//apr_file manager +//which: 1)only keeps one file open; +// 2)closes the open file in the destruction function +// 3)informs the apr_pool to clean the memory when the file is closed. +//Note: please close an open file at the earliest convenience. +// especially do not put some time-costly operations between open() and close(). +// otherwise it might lock the APRFilePool. +//there are two different apr_pools the APRFile can use: +// 1, a temperary pool passed to an APRFile function, which is used within this function and only once. +// 2, a global pool. +// +class LL_COMMON_API LLAPRFile +{ +private: + apr_file_t* mFile ; + LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + +public: + LLAPRFile() ; + ~LLAPRFile() ; + + apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL); + apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL); + apr_status_t close() ; + + // Returns actual offset, -1 if seek fails + S32 seek(apr_seek_where_t where, S32 offset); + apr_status_t eof() { return apr_file_eof(mFile);} + + // Returns bytes read/written, 0 if read/write fails: + S32 read(void* buf, S32 nbytes); + S32 write(const void* buf, S32 nbytes); + + apr_file_t* getFileHandle() {return mFile;} + +private: + apr_pool_t* getAPRFilePool(apr_pool_t* pool) ; + +// +//******************************************************************************************************************************* +//static components +// +public: + static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. + +private: + static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags); + static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ; + static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); +public: + // returns false if failure: + static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); + static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); + static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + + // Returns bytes read/written, 0 if read/write fails: + static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); + static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); +//******************************************************************************************************************************* +}; + +/** + * @brief Function which approprately logs error or remains quiet on + * APR_SUCCESS. + * @return Returns <code>true</code> if status is an error condition. + */ +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); + +void LL_COMMON_API ll_apr_assert_status(apr_status_t status); + +extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool + +#endif // LL_LLAPR_H diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 33705cd2b1bc36a5e6d4e5c8100e0725b4b472c3..3c760e4d9171c2c344c88af2316df3e9126dda71 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -1,205 +1,205 @@ -/** - * @file llassettype.h - * @brief Declaration of LLAssetType. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLASSETTYPE_H -#define LL_LLASSETTYPE_H - -#include <string> - -#include "stdenums.h" // for EDragAndDropType - -class LL_COMMON_API LLAssetType -{ -public: - enum EType - { - AT_TEXTURE = 0, - // Used for painting the faces of geometry. - // Stored in typical j2c stream format. - - AT_SOUND = 1, - // Used to fill the aural spectrum. - - AT_CALLINGCARD = 2, - // Links instant message access to the user on the card. - // : E.G. A card for yourself, for linden support, for - // : the guy you were talking to in the coliseum. - - AT_LANDMARK = 3, - // Links to places in the world with location and a screen shot or image saved. - // : E.G. Home, linden headquarters, the coliseum, destinations where - // : we want to increase traffic. - - AT_SCRIPT = 4, - // Valid scripts that can be attached to an object. - // : E.G. Open a door, jump into the air. - - AT_CLOTHING = 5, - // A collection of textures and parameters that can be worn by an avatar. - - AT_OBJECT = 6, - // Any combination of textures, sounds, and scripts that are - // associated with a fixed piece of geometry. - // : E.G. A hot tub, a house with working door. - - AT_NOTECARD = 7, - // Just text. - - AT_CATEGORY = 8, - // Holds a collection of inventory items. - // It's treated as an item in the inventory and therefore needs a type. - - AT_ROOT_CATEGORY = 9, - // A user's root inventory category. - // We decided to expose it visually, so it seems logical to fold - // it into the asset types. - - AT_LSL_TEXT = 10, - AT_LSL_BYTECODE = 11, - // The LSL is the scripting language. - // We've split it into a text and bytecode representation. - - AT_TEXTURE_TGA = 12, - // Uncompressed TGA texture. - - AT_BODYPART = 13, - // A collection of textures and parameters that can be worn by an avatar. - - AT_TRASH = 14, - // Only to be used as a marker for a category preferred type. - // Using this, we can throw things in the trash before completely deleting. - - AT_SNAPSHOT_CATEGORY = 15, - // A marker for a folder meant for snapshots. - // No actual assets will be snapshots, though if there were, you - // could interpret them as textures. - - AT_LOST_AND_FOUND = 16, - // Used to stuff lost&found items into. - - AT_SOUND_WAV = 17, - // Uncompressed sound. - - AT_IMAGE_TGA = 18, - // Uncompressed image, non-square. - // Not appropriate for use as a texture. - - AT_IMAGE_JPEG = 19, - // Compressed image, non-square. - // Not appropriate for use as a texture. - - AT_ANIMATION = 20, - // Animation. - - AT_GESTURE = 21, - // Gesture, sequence of animations, sounds, chat, wait steps. - - AT_SIMSTATE = 22, - // Simstate file. - - AT_FAVORITE = 23, - // favorite items - - AT_LINK = 24, - // Inventory symbolic link - - AT_LINK_FOLDER = 25, - // Inventory folder link - - AT_FOLDER_ENSEMBLE_START = 26, - AT_FOLDER_ENSEMBLE_END = 45, - // This range is reserved for special clothing folder types. - - AT_CURRENT_OUTFIT = 46, - // Current outfit - - AT_OUTFIT = 47, - // Predefined outfit ("look") - - AT_MY_OUTFITS = 48, - // Folder that holds your outfits. - - - AT_COUNT = 49, - - // +*********************************************************+ - // | TO ADD AN ELEMENT TO THIS ENUM: | - // +*********************************************************+ - // | 1. INSERT BEFORE AT_COUNT | - // | 2. INCREMENT AT_COUNT BY 1 | - // | 3. ADD TO LLAssetDictionary in LLAssetType.cpp | - // | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | - // +*********************************************************+ - - AT_NONE = -1 - }; - - // machine transation between type and strings - static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate - static EType lookup(const std::string& type_name); - static const char* lookup(EType asset_type); - - // translation from a type to a human readable form. - static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate - static EType lookupHumanReadable(const std::string& readable_name); - static const char* lookupHumanReadable(EType asset_type); - - // Generate a good default description. You may want to add a verb - // or agent name after this depending on your application. - static void generateDescriptionFor(LLAssetType::EType asset_type, - std::string& description); - - static EType getType(const std::string& desc_name); - static const std::string& getDesc(EType asset_type); - static EDragAndDropType lookupDragAndDropType(EType asset_type); - - static bool lookupCanLink(EType asset_type); - static bool lookupIsLinkType(EType asset_type); - - static const char* lookupCategoryName(EType asset_type); - static bool lookupIsProtectedCategoryType(EType asset_type); - static bool lookupIsEnsembleCategoryType(EType asset_type); - - /* TODO: Change return types from "const char *" to "const std::string &". - This is fairly straightforward, but requires changing some calls to use .c_str(). - e.g.: - - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - + fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str()); - */ - -private: - // don't instantiate or derive one of these objects - LLAssetType( void ) {} - ~LLAssetType( void ) {} -}; - -#endif // LL_LLASSETTYPE_H +/** + * @file llassettype.h + * @brief Declaration of LLAssetType. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLASSETTYPE_H +#define LL_LLASSETTYPE_H + +#include <string> + +#include "stdenums.h" // for EDragAndDropType + +class LL_COMMON_API LLAssetType +{ +public: + enum EType + { + AT_TEXTURE = 0, + // Used for painting the faces of geometry. + // Stored in typical j2c stream format. + + AT_SOUND = 1, + // Used to fill the aural spectrum. + + AT_CALLINGCARD = 2, + // Links instant message access to the user on the card. + // : E.G. A card for yourself, for linden support, for + // : the guy you were talking to in the coliseum. + + AT_LANDMARK = 3, + // Links to places in the world with location and a screen shot or image saved. + // : E.G. Home, linden headquarters, the coliseum, destinations where + // : we want to increase traffic. + + AT_SCRIPT = 4, + // Valid scripts that can be attached to an object. + // : E.G. Open a door, jump into the air. + + AT_CLOTHING = 5, + // A collection of textures and parameters that can be worn by an avatar. + + AT_OBJECT = 6, + // Any combination of textures, sounds, and scripts that are + // associated with a fixed piece of geometry. + // : E.G. A hot tub, a house with working door. + + AT_NOTECARD = 7, + // Just text. + + AT_CATEGORY = 8, + // Holds a collection of inventory items. + // It's treated as an item in the inventory and therefore needs a type. + + AT_ROOT_CATEGORY = 9, + // A user's root inventory category. + // We decided to expose it visually, so it seems logical to fold + // it into the asset types. + + AT_LSL_TEXT = 10, + AT_LSL_BYTECODE = 11, + // The LSL is the scripting language. + // We've split it into a text and bytecode representation. + + AT_TEXTURE_TGA = 12, + // Uncompressed TGA texture. + + AT_BODYPART = 13, + // A collection of textures and parameters that can be worn by an avatar. + + AT_TRASH = 14, + // Only to be used as a marker for a category preferred type. + // Using this, we can throw things in the trash before completely deleting. + + AT_SNAPSHOT_CATEGORY = 15, + // A marker for a folder meant for snapshots. + // No actual assets will be snapshots, though if there were, you + // could interpret them as textures. + + AT_LOST_AND_FOUND = 16, + // Used to stuff lost&found items into. + + AT_SOUND_WAV = 17, + // Uncompressed sound. + + AT_IMAGE_TGA = 18, + // Uncompressed image, non-square. + // Not appropriate for use as a texture. + + AT_IMAGE_JPEG = 19, + // Compressed image, non-square. + // Not appropriate for use as a texture. + + AT_ANIMATION = 20, + // Animation. + + AT_GESTURE = 21, + // Gesture, sequence of animations, sounds, chat, wait steps. + + AT_SIMSTATE = 22, + // Simstate file. + + AT_FAVORITE = 23, + // favorite items + + AT_LINK = 24, + // Inventory symbolic link + + AT_LINK_FOLDER = 25, + // Inventory folder link + + AT_FOLDER_ENSEMBLE_START = 26, + AT_FOLDER_ENSEMBLE_END = 45, + // This range is reserved for special clothing folder types. + + AT_CURRENT_OUTFIT = 46, + // Current outfit + + AT_OUTFIT = 47, + // Predefined outfit ("look") + + AT_MY_OUTFITS = 48, + // Folder that holds your outfits. + + + AT_COUNT = 49, + + // +*********************************************************+ + // | TO ADD AN ELEMENT TO THIS ENUM: | + // +*********************************************************+ + // | 1. INSERT BEFORE AT_COUNT | + // | 2. INCREMENT AT_COUNT BY 1 | + // | 3. ADD TO LLAssetDictionary in LLAssetType.cpp | + // | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | + // +*********************************************************+ + + AT_NONE = -1 + }; + + // machine transation between type and strings + static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate + static EType lookup(const std::string& type_name); + static const char* lookup(EType asset_type); + + // translation from a type to a human readable form. + static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate + static EType lookupHumanReadable(const std::string& readable_name); + static const char* lookupHumanReadable(EType asset_type); + + // Generate a good default description. You may want to add a verb + // or agent name after this depending on your application. + static void generateDescriptionFor(LLAssetType::EType asset_type, + std::string& description); + + static EType getType(const std::string& desc_name); + static const std::string& getDesc(EType asset_type); + static EDragAndDropType lookupDragAndDropType(EType asset_type); + + static bool lookupCanLink(EType asset_type); + static bool lookupIsLinkType(EType asset_type); + + static const char* lookupCategoryName(EType asset_type); + static bool lookupIsProtectedCategoryType(EType asset_type); + static bool lookupIsEnsembleCategoryType(EType asset_type); + + /* TODO: Change return types from "const char *" to "const std::string &". + This is fairly straightforward, but requires changing some calls to use .c_str(). + e.g.: + - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); + + fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str()); + */ + +private: + // don't instantiate or derive one of these objects + LLAssetType( void ) {} + ~LLAssetType( void ) {} +}; + +#endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 6c5fa5af6d6884908d36fcbd64e0510a72de6a7d..141b0df43cfbc9581abe6f5d141f1f47423d1ce4 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -1,149 +1,149 @@ -/** - * @file llcoros.h - * @author Nat Goodspeed - * @date 2009-06-02 - * @brief Manage running boost::coroutine instances - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * Copyright (c) 2009, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLCOROS_H) -#define LL_LLCOROS_H - -#include <boost/coroutine/coroutine.hpp> -#include "llsingleton.h" -#include <boost/ptr_container/ptr_map.hpp> -#include <string> -#include <boost/preprocessor/repetition/enum_params.hpp> -#include <boost/preprocessor/repetition/enum_binary_params.hpp> -#include <boost/preprocessor/iteration/local.hpp> -#include <stdexcept> - -/** - * Registry of named Boost.Coroutine instances - * - * The Boost.Coroutine library supports the general case of a coroutine - * accepting arbitrary parameters and yielding multiple (sets of) results. For - * such use cases, it's natural for the invoking code to retain the coroutine - * instance: the consumer repeatedly calls into the coroutine, perhaps passing - * new parameter values, prompting it to yield its next result. - * - * Our typical coroutine usage is different, though. For us, coroutines - * provide an alternative to the @c Responder pattern. Our typical coroutine - * has @c void return, invoked in fire-and-forget mode: the handler for some - * user gesture launches the coroutine and promptly returns to the main loop. - * The coroutine initiates some action that will take multiple frames (e.g. a - * capability request), waits for its result, processes it and silently steals - * away. - * - * This usage poses two (related) problems: - * - * # Who should own the coroutine instance? If it's simply local to the - * handler code that launches it, return from the handler will destroy the - * coroutine object, terminating the coroutine. - * # Once the coroutine terminates, in whatever way, who's responsible for - * cleaning up the coroutine object? - * - * LLCoros is a Singleton collection of currently-active coroutine instances. - * Each has a name. You ask LLCoros to launch a new coroutine with a suggested - * name prefix; from your prefix it generates a distinct name, registers the - * new coroutine and returns the actual name. - * - * The name can be used to kill off the coroutine prematurely, if needed. It - * can also provide diagnostic info: we can look up the name of the - * currently-running coroutine. - * - * Finally, the next frame ("mainloop" event) after the coroutine terminates, - * LLCoros will notice its demise and destroy it. - */ -class LL_COMMON_API LLCoros: public LLSingleton<LLCoros> -{ -public: - /// Canonical boost::coroutines::coroutine signature we use - typedef boost::coroutines::coroutine<void()> coro; - /// Canonical 'self' type - typedef coro::self self; - - /** - * Create and start running a new coroutine with specified name. The name - * string you pass is a suggestion; it will be tweaked for uniqueness. The - * actual name is returned to you. - * - * Usage looks like this, for (e.g.) two coroutine parameters: - * @code - * class MyClass - * { - * public: - * ... - * // Do NOT NOT NOT accept reference params other than 'self'! - * // Pass by value only! - * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD); - * ... - * }; - * ... - * std::string name = LLCoros::instance().launch( - * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1, - * "somestring", LLSD(17)); - * @endcode - * - * Your function/method must accept LLCoros::self& as its first parameter. - * It can accept any other parameters you want -- but ONLY BY VALUE! - * Other reference parameters are a BAD IDEA! You Have Been Warned. See - * DEV-32777 comments for an explanation. - * - * Pass a callable that accepts the single LLCoros::self& parameter. It - * may work to pass a free function whose only parameter is 'self'; for - * all other cases use boost::bind(). Of course, for a non-static class - * method, the first parameter must be the class instance. Use the - * placeholder _1 for the 'self' parameter. Any other parameters should be - * passed via the bind() expression. - * - * launch() tweaks the suggested name so it won't collide with any - * existing coroutine instance, creates the coroutine instance, registers - * it with the tweaked name and runs it until its first wait. At that - * point it returns the tweaked name. - */ - template <typename CALLABLE> - std::string launch(const std::string& prefix, const CALLABLE& callable) - { - return launchImpl(prefix, new coro(callable)); - } - - /** - * Abort a running coroutine by name. Normally, when a coroutine either - * runs to completion or terminates with an exception, LLCoros quietly - * cleans it up. This is for use only when you must explicitly interrupt - * one prematurely. Returns @c true if the specified name was found and - * still running at the time. - */ - bool kill(const std::string& name); - - /** - * From within a coroutine, pass its @c self object to look up the - * (tweaked) name string by which this coroutine is registered. Returns - * the empty string if not found (e.g. if the coroutine was launched by - * hand rather than using LLCoros::launch()). - */ - template <typename COROUTINE_SELF> - std::string getName(const COROUTINE_SELF& self) const - { - return getNameByID(self.get_id()); - } - - /// getName() by self.get_id() - std::string getNameByID(const void* self_id) const; - -private: - friend class LLSingleton<LLCoros>; - LLCoros(); - std::string launchImpl(const std::string& prefix, coro* newCoro); - std::string generateDistinctName(const std::string& prefix) const; - bool cleanup(const LLSD&); - - typedef boost::ptr_map<std::string, coro> CoroMap; - CoroMap mCoros; -}; - -#endif /* ! defined(LL_LLCOROS_H) */ +/** + * @file llcoros.h + * @author Nat Goodspeed + * @date 2009-06-02 + * @brief Manage running boost::coroutine instances + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLCOROS_H) +#define LL_LLCOROS_H + +#include <boost/coroutine/coroutine.hpp> +#include "llsingleton.h" +#include <boost/ptr_container/ptr_map.hpp> +#include <string> +#include <boost/preprocessor/repetition/enum_params.hpp> +#include <boost/preprocessor/repetition/enum_binary_params.hpp> +#include <boost/preprocessor/iteration/local.hpp> +#include <stdexcept> + +/** + * Registry of named Boost.Coroutine instances + * + * The Boost.Coroutine library supports the general case of a coroutine + * accepting arbitrary parameters and yielding multiple (sets of) results. For + * such use cases, it's natural for the invoking code to retain the coroutine + * instance: the consumer repeatedly calls into the coroutine, perhaps passing + * new parameter values, prompting it to yield its next result. + * + * Our typical coroutine usage is different, though. For us, coroutines + * provide an alternative to the @c Responder pattern. Our typical coroutine + * has @c void return, invoked in fire-and-forget mode: the handler for some + * user gesture launches the coroutine and promptly returns to the main loop. + * The coroutine initiates some action that will take multiple frames (e.g. a + * capability request), waits for its result, processes it and silently steals + * away. + * + * This usage poses two (related) problems: + * + * # Who should own the coroutine instance? If it's simply local to the + * handler code that launches it, return from the handler will destroy the + * coroutine object, terminating the coroutine. + * # Once the coroutine terminates, in whatever way, who's responsible for + * cleaning up the coroutine object? + * + * LLCoros is a Singleton collection of currently-active coroutine instances. + * Each has a name. You ask LLCoros to launch a new coroutine with a suggested + * name prefix; from your prefix it generates a distinct name, registers the + * new coroutine and returns the actual name. + * + * The name can be used to kill off the coroutine prematurely, if needed. It + * can also provide diagnostic info: we can look up the name of the + * currently-running coroutine. + * + * Finally, the next frame ("mainloop" event) after the coroutine terminates, + * LLCoros will notice its demise and destroy it. + */ +class LL_COMMON_API LLCoros: public LLSingleton<LLCoros> +{ +public: + /// Canonical boost::coroutines::coroutine signature we use + typedef boost::coroutines::coroutine<void()> coro; + /// Canonical 'self' type + typedef coro::self self; + + /** + * Create and start running a new coroutine with specified name. The name + * string you pass is a suggestion; it will be tweaked for uniqueness. The + * actual name is returned to you. + * + * Usage looks like this, for (e.g.) two coroutine parameters: + * @code + * class MyClass + * { + * public: + * ... + * // Do NOT NOT NOT accept reference params other than 'self'! + * // Pass by value only! + * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD); + * ... + * }; + * ... + * std::string name = LLCoros::instance().launch( + * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1, + * "somestring", LLSD(17)); + * @endcode + * + * Your function/method must accept LLCoros::self& as its first parameter. + * It can accept any other parameters you want -- but ONLY BY VALUE! + * Other reference parameters are a BAD IDEA! You Have Been Warned. See + * DEV-32777 comments for an explanation. + * + * Pass a callable that accepts the single LLCoros::self& parameter. It + * may work to pass a free function whose only parameter is 'self'; for + * all other cases use boost::bind(). Of course, for a non-static class + * method, the first parameter must be the class instance. Use the + * placeholder _1 for the 'self' parameter. Any other parameters should be + * passed via the bind() expression. + * + * launch() tweaks the suggested name so it won't collide with any + * existing coroutine instance, creates the coroutine instance, registers + * it with the tweaked name and runs it until its first wait. At that + * point it returns the tweaked name. + */ + template <typename CALLABLE> + std::string launch(const std::string& prefix, const CALLABLE& callable) + { + return launchImpl(prefix, new coro(callable)); + } + + /** + * Abort a running coroutine by name. Normally, when a coroutine either + * runs to completion or terminates with an exception, LLCoros quietly + * cleans it up. This is for use only when you must explicitly interrupt + * one prematurely. Returns @c true if the specified name was found and + * still running at the time. + */ + bool kill(const std::string& name); + + /** + * From within a coroutine, pass its @c self object to look up the + * (tweaked) name string by which this coroutine is registered. Returns + * the empty string if not found (e.g. if the coroutine was launched by + * hand rather than using LLCoros::launch()). + */ + template <typename COROUTINE_SELF> + std::string getName(const COROUTINE_SELF& self) const + { + return getNameByID(self.get_id()); + } + + /// getName() by self.get_id() + std::string getNameByID(const void* self_id) const; + +private: + friend class LLSingleton<LLCoros>; + LLCoros(); + std::string launchImpl(const std::string& prefix, coro* newCoro); + std::string generateDistinctName(const std::string& prefix) const; + bool cleanup(const LLSD&); + + typedef boost::ptr_map<std::string, coro> CoroMap; + CoroMap mCoros; +}; + +#endif /* ! defined(LL_LLCOROS_H) */ diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index 671f2a4d1cf19944a659d9d3e21704db4485db63..5a86b90bff1924a5357b843f3dab622df4262a39 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -1,130 +1,130 @@ -/** - * @file lleventdispatcher.h - * @author Nat Goodspeed - * @date 2009-06-18 - * @brief Central mechanism for dispatching events by string name. This is - * useful when you have a single LLEventPump listener on which you can - * request different operations, vs. instantiating a different - * LLEventPump for each such operation. - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * Copyright (c) 2009, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLEVENTDISPATCHER_H) -#define LL_LLEVENTDISPATCHER_H - -#include <string> -#include <map> -#include <boost/function.hpp> -#include <boost/bind.hpp> -#include <typeinfo> -#include "llevents.h" - -class LLSD; - -/** - * Given an LLSD map, examine a string-valued key and call a corresponding - * callable. This class is designed to be contained by an LLEventPump - * listener class that will register some of its own methods, though any - * callable can be used. - */ -class LL_COMMON_API LLEventDispatcher -{ -public: - LLEventDispatcher(const std::string& desc, const std::string& key); - virtual ~LLEventDispatcher(); - - /// Accept any C++ callable, typically a boost::bind() expression - typedef boost::function<void(const LLSD&)> Callable; - - /** - * Register a @a callable by @a name. The optional @a required parameter - * is used to validate the structure of each incoming event (see - * llsd_matches()). - */ - void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD()); - - /** - * Special case: a subclass of this class can pass an unbound member - * function pointer without explicitly specifying the - * <tt>boost::bind()</tt> expression. - */ - template <class CLASS> - void add(const std::string& name, void (CLASS::*method)(const LLSD&), - const LLSD& required=LLSD()) - { - addMethod<CLASS>(name, method, required); - } - - /// Overload for both const and non-const methods - template <class CLASS> - void add(const std::string& name, void (CLASS::*method)(const LLSD&) const, - const LLSD& required=LLSD()) - { - addMethod<CLASS>(name, method, required); - } - - /// Unregister a callable - bool remove(const std::string& name); - - /// Call a registered callable with an explicitly-specified name. If no - /// such callable exists, die with LL_ERRS. If the @a event fails to match - /// the @a required prototype specified at add() time, die with LL_ERRS. - void operator()(const std::string& name, const LLSD& event) const; - - /// Extract the @a key value from the incoming @a event, and call the - /// callable whose name is specified by that map @a key. If no such - /// callable exists, die with LL_ERRS. If the @a event fails to match the - /// @a required prototype specified at add() time, die with LL_ERRS. - void operator()(const LLSD& event) const; - - /// Fetch the Callable for the specified name. If no such name was - /// registered, return an empty() Callable. - Callable get(const std::string& name) const; - -private: - template <class CLASS, typename METHOD> - void addMethod(const std::string& name, const METHOD& method, const LLSD& required) - { - CLASS* downcast = dynamic_cast<CLASS*>(this); - if (! downcast) - { - addFail(name, typeid(CLASS).name()); - } - else - { - add(name, boost::bind(method, downcast, _1), required); - } - } - void addFail(const std::string& name, const std::string& classname) const; - /// try to dispatch, return @c true if success - bool attemptCall(const std::string& name, const LLSD& event) const; - - std::string mDesc, mKey; - typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap; - DispatchMap mDispatch; -}; - -/** - * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class - * that contains (or derives from) LLDispatchListener need only specify the - * LLEventPump name and dispatch key, and add() its methods. Incoming events - * will automatically be dispatched. - */ -class LL_COMMON_API LLDispatchListener: public LLEventDispatcher -{ -public: - LLDispatchListener(const std::string& pumpname, const std::string& key); - - std::string getPumpName() const { return mPump.getName(); } - -private: - bool process(const LLSD& event); - - LLEventStream mPump; - LLTempBoundListener mBoundListener; -}; - -#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */ +/** + * @file lleventdispatcher.h + * @author Nat Goodspeed + * @date 2009-06-18 + * @brief Central mechanism for dispatching events by string name. This is + * useful when you have a single LLEventPump listener on which you can + * request different operations, vs. instantiating a different + * LLEventPump for each such operation. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLEVENTDISPATCHER_H) +#define LL_LLEVENTDISPATCHER_H + +#include <string> +#include <map> +#include <boost/function.hpp> +#include <boost/bind.hpp> +#include <typeinfo> +#include "llevents.h" + +class LLSD; + +/** + * Given an LLSD map, examine a string-valued key and call a corresponding + * callable. This class is designed to be contained by an LLEventPump + * listener class that will register some of its own methods, though any + * callable can be used. + */ +class LL_COMMON_API LLEventDispatcher +{ +public: + LLEventDispatcher(const std::string& desc, const std::string& key); + virtual ~LLEventDispatcher(); + + /// Accept any C++ callable, typically a boost::bind() expression + typedef boost::function<void(const LLSD&)> Callable; + + /** + * Register a @a callable by @a name. The optional @a required parameter + * is used to validate the structure of each incoming event (see + * llsd_matches()). + */ + void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD()); + + /** + * Special case: a subclass of this class can pass an unbound member + * function pointer without explicitly specifying the + * <tt>boost::bind()</tt> expression. + */ + template <class CLASS> + void add(const std::string& name, void (CLASS::*method)(const LLSD&), + const LLSD& required=LLSD()) + { + addMethod<CLASS>(name, method, required); + } + + /// Overload for both const and non-const methods + template <class CLASS> + void add(const std::string& name, void (CLASS::*method)(const LLSD&) const, + const LLSD& required=LLSD()) + { + addMethod<CLASS>(name, method, required); + } + + /// Unregister a callable + bool remove(const std::string& name); + + /// Call a registered callable with an explicitly-specified name. If no + /// such callable exists, die with LL_ERRS. If the @a event fails to match + /// the @a required prototype specified at add() time, die with LL_ERRS. + void operator()(const std::string& name, const LLSD& event) const; + + /// Extract the @a key value from the incoming @a event, and call the + /// callable whose name is specified by that map @a key. If no such + /// callable exists, die with LL_ERRS. If the @a event fails to match the + /// @a required prototype specified at add() time, die with LL_ERRS. + void operator()(const LLSD& event) const; + + /// Fetch the Callable for the specified name. If no such name was + /// registered, return an empty() Callable. + Callable get(const std::string& name) const; + +private: + template <class CLASS, typename METHOD> + void addMethod(const std::string& name, const METHOD& method, const LLSD& required) + { + CLASS* downcast = dynamic_cast<CLASS*>(this); + if (! downcast) + { + addFail(name, typeid(CLASS).name()); + } + else + { + add(name, boost::bind(method, downcast, _1), required); + } + } + void addFail(const std::string& name, const std::string& classname) const; + /// try to dispatch, return @c true if success + bool attemptCall(const std::string& name, const LLSD& event) const; + + std::string mDesc, mKey; + typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap; + DispatchMap mDispatch; +}; + +/** + * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class + * that contains (or derives from) LLDispatchListener need only specify the + * LLEventPump name and dispatch key, and add() its methods. Incoming events + * will automatically be dispatched. + */ +class LL_COMMON_API LLDispatchListener: public LLEventDispatcher +{ +public: + LLDispatchListener(const std::string& pumpname, const std::string& key); + + std::string getPumpName() const { return mPump.getName(); } + +private: + bool process(const LLSD& event); + + LLEventStream mPump; + LLTempBoundListener mBoundListener; +}; + +#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */ diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 64e5cb5da7f290134b89f988e806f71dcd16f0b0..192d79b27ddb2658c4fda32c1fdc1d83d8502588 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -1,943 +1,943 @@ -/** - * @file llevents.h - * @author Kent Quirk, Nat Goodspeed - * @date 2008-09-11 - * @brief This is an implementation of the event system described at - * 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=viewergpl$ - * Copyright (c) 2008, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLEVENTS_H) -#define LL_LLEVENTS_H - -#include <string> -#include <map> -#include <set> -#include <vector> -#include <deque> -#include <stdexcept> -#if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) -#endif -#include <boost/signals2.hpp> -#if LL_WINDOWS - #pragma warning (pop) -#endif - -#include <boost/bind.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/enable_shared_from_this.hpp> -#include <boost/utility.hpp> // noncopyable -#include <boost/optional/optional.hpp> -#include <boost/visit_each.hpp> -#include <boost/ref.hpp> // reference_wrapper -#include <boost/type_traits/is_pointer.hpp> -#include <boost/function.hpp> -#include <boost/static_assert.hpp> -#include "llsd.h" -#include "llsingleton.h" -#include "lldependencies.h" - -// override this to allow binding free functions with more parameters -#ifndef LLEVENTS_LISTENER_ARITY -#define LLEVENTS_LISTENER_ARITY 10 -#endif - -// hack for testing -#ifndef testable -#define testable private -#endif - -/***************************************************************************** -* Signal and handler declarations -* Using a single handler signature means that we can have a common handler -* type, rather than needing a distinct one for each different handler. -*****************************************************************************/ - -/** - * A boost::signals Combiner that stops the first time a handler returns true - * We need this because we want to have our handlers return bool, so that - * we have the option to cause a handler to stop further processing. The - * default handler fails when the signal returns a value but has no slots. - */ -struct LLStopWhenHandled -{ - typedef bool result_type; - - template<typename InputIterator> - result_type operator()(InputIterator first, InputIterator last) const - { - for (InputIterator si = first; si != last; ++si) - { - if (*si) - { - return true; - } - } - return false; - } -}; - -/** - * We want to have a standard signature for all signals; this way, - * we can easily document a protocol for communicating across - * dlls and into scripting languages someday. - * - * We want to return a bool to indicate whether the signal has been - * handled and should NOT be passed on to other listeners. - * Return true to stop further handling of the signal, and false - * to continue. - * - * We take an LLSD because this way the contents of the signal - * are independent of the API used to communicate it. - * It is const ref because then there's low cost to pass it; - * if you only need to inspect it, it's very cheap. - * - * @internal - * The @c float template parameter indicates that we will internally use @c - * float to indicate relative listener order on a given LLStandardSignal. - * Don't worry, the @c float values are strictly internal! They are not part - * of the interface, for the excellent reason that requiring the caller to - * specify a numeric key to establish order means that the caller must know - * the universe of possible values. We use LLDependencies for that instead. - */ -typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LLStandardSignal; -/// Methods that forward listeners (e.g. constructed with -/// <tt>boost::bind()</tt>) should accept (const LLEventListener&) -typedef LLStandardSignal::slot_type LLEventListener; -/// Result of registering a listener, supports <tt>connected()</tt>, -/// <tt>disconnect()</tt> and <tt>blocked()</tt> -typedef boost::signals2::connection LLBoundListener; -/// Storing an LLBoundListener in LLTempBoundListener will disconnect the -/// referenced listener when the LLTempBoundListener instance is destroyed. -typedef boost::signals2::scoped_connection LLTempBoundListener; - -/** - * A common idiom for event-based code is to accept either a callable -- - * directly called on completion -- or the string name of an LLEventPump on - * which to post the completion event. Specifying a parameter as <tt>const - * LLListenerOrPumpName&</tt> allows either. - * - * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD - * 'event' object, either calls the callable or posts the event to the named - * LLEventPump. - * - * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as - * the default value of an optional method parameter.) Calling it throws - * LLListenerOrPumpName::Empty. Test for this condition beforehand using - * either <tt>if (param)</tt> or <tt>if (! param)</tt>. - */ -class LL_COMMON_API LLListenerOrPumpName -{ -public: - /// passing string name of LLEventPump - LLListenerOrPumpName(const std::string& pumpname); - /// passing string literal (overload so compiler isn't forced to infer - /// double conversion) - LLListenerOrPumpName(const char* pumpname); - /// passing listener -- the "anything else" catch-all case. The type of an - /// object constructed by boost::bind() isn't intended to be written out. - /// Normally we'd just accept 'const LLEventListener&', but that would - /// require double implicit conversion: boost::bind() object to - /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a - /// template to forward anything. - template<typename T> - LLListenerOrPumpName(const T& listener): mListener(listener) {} - - /// for omitted method parameter: uninitialized mListener - LLListenerOrPumpName() {} - - /// test for validity - operator bool() const { return bool(mListener); } - bool operator! () const { return ! mListener; } - - /// explicit accessor - const LLEventListener& getListener() const { return *mListener; } - - /// implicit conversion to LLEventListener - operator LLEventListener() const { return *mListener; } - - /// allow calling directly - bool operator()(const LLSD& event) const; - - /// exception if you try to call when empty - struct Empty: public std::runtime_error - { - Empty(const std::string& what): - std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {} - }; - -private: - boost::optional<LLEventListener> mListener; -}; - -/***************************************************************************** -* LLEventPumps -*****************************************************************************/ -class LLEventPump; - -/** - * LLEventPumps is a Singleton manager through which one typically accesses - * this subsystem. - */ -class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps> -{ - friend class LLSingleton<LLEventPumps>; -public: - /** - * Find or create an LLEventPump instance with a specific name. We return - * a reference so there's no question about ownership. obtain() @em finds - * an instance without conferring @em ownership. - */ - LLEventPump& obtain(const std::string& name); - /** - * Flush all known LLEventPump instances - */ - void flush(); - - /** - * Reset all known LLEventPump instances - * workaround for DEV-35406 crash on shutdown - */ - void reset(); - -private: - friend class LLEventPump; - /** - * Register a new LLEventPump instance (internal) - */ - std::string registerNew(const LLEventPump&, const std::string& name, bool tweak); - /** - * Unregister a doomed LLEventPump instance (internal) - */ - void unregister(const LLEventPump&); - -private: - LLEventPumps(); - ~LLEventPumps(); - -testable: - // Map of all known LLEventPump instances, whether or not we instantiated - // them. We store a plain old LLEventPump* because this map doesn't claim - // ownership of the instances. Though the common usage pattern is to - // request an instance using obtain(), it's fair to instantiate an - // LLEventPump subclass statically, as a class member, on the stack or on - // the heap. In such cases, the instantiating party is responsible for its - // lifespan. - typedef std::map<std::string, LLEventPump*> PumpMap; - PumpMap mPumpMap; - // Set of all LLEventPumps we instantiated. Membership in this set means - // we claim ownership, and will delete them when this LLEventPumps is - // destroyed. - typedef std::set<LLEventPump*> PumpSet; - PumpSet mOurPumps; - // LLEventPump names that should be instantiated as LLEventQueue rather - // than as LLEventStream - typedef std::set<std::string> PumpNames; - PumpNames mQueueNames; -}; - -/***************************************************************************** -* details -*****************************************************************************/ -namespace LLEventDetail -{ - /// Any callable capable of connecting an LLEventListener to an - /// LLStandardSignal to produce an LLBoundListener can be mapped to this - /// signature. - typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc; - - /** - * Utility template function to use Visitor appropriately - * - * @param listener Callable to connect, typically a boost::bind() - * expression. This will be visited by Visitor using boost::visit_each(). - * @param connect_func Callable that will connect() @a listener to an - * LLStandardSignal, returning LLBoundListener. - */ - template <typename LISTENER> - LLBoundListener visit_and_connect(const LISTENER& listener, - const ConnectFunc& connect_func); -} // namespace LLEventDetail - -/***************************************************************************** -* LLEventTrackable -*****************************************************************************/ -/** - * LLEventTrackable wraps boost::signals2::trackable, which resembles - * boost::trackable. Derive your listener class from LLEventTrackable instead, - * and use something like - * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method, - * instance, _1))</tt>. This will implicitly disconnect when the object - * referenced by @c instance is destroyed. - * - * @note - * LLEventTrackable doesn't address a couple of cases: - * * Object destroyed during call - * - You enter a slot call in thread A. - * - Thread B destroys the object, which of course disconnects it from any - * future slot calls. - * - Thread A's call uses 'this', which now refers to a defunct object. - * Undefined behavior results. - * * Call during destruction - * - @c MySubclass is derived from LLEventTrackable. - * - @c MySubclass registers one of its own methods using - * <tt>LLEventPump::listen()</tt>. - * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt> - * runs, destroying state specific to the subclass. (For instance, a - * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.) - * - The listening method will not be disconnected until - * <tt>~LLEventTrackable()</tt> runs. - * - Before we get there, another thread posts data to the @c LLEventPump - * instance, calling the @c MySubclass method. - * - The method in question relies on valid @c MySubclass state. (For - * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was - * <tt>delete</tt>d but not zeroed.) - * - Undefined behavior results. - * If you suspect you may encounter any such scenario, you're better off - * managing the lifespan of your object with <tt>boost::shared_ptr</tt>. - * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression - * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging - * thread-safe Boost.Signals2 machinery. - */ -typedef boost::signals2::trackable LLEventTrackable; - -/***************************************************************************** -* LLEventPump -*****************************************************************************/ -/** - * LLEventPump is the base class interface through which we access the - * concrete subclasses LLEventStream and LLEventQueue. - * - * @NOTE - * LLEventPump derives from LLEventTrackable so that when you "chain" - * LLEventPump instances together, they will automatically disconnect on - * destruction. Please see LLEventTrackable documentation for situations in - * which this may be perilous across threads. - */ -class LL_COMMON_API LLEventPump: public LLEventTrackable -{ -public: - /** - * Exception thrown by LLEventPump(). You are trying to instantiate an - * LLEventPump (subclass) using the same name as some other instance, and - * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique - * variant. - */ - struct DupPumpName: public std::runtime_error - { - DupPumpName(const std::string& what): - std::runtime_error(std::string("DupPumpName: ") + what) {} - }; - - /** - * Instantiate an LLEventPump (subclass) with the string name by which it - * can be found using LLEventPumps::obtain(). - * - * If you pass (or default) @a tweak to @c false, then a duplicate name - * will throw DupPumpName. This won't happen if LLEventPumps::obtain() - * instantiates the LLEventPump, because obtain() uses find-or-create - * logic. It can only happen if you instantiate an LLEventPump in your own - * code -- and a collision with the name of some other LLEventPump is - * likely to cause much more subtle problems! - * - * When you hand-instantiate an LLEventPump, consider passing @a tweak as - * @c true. This directs LLEventPump() to append a suffix to the passed @a - * name to make it unique. You can retrieve the adjusted name by calling - * getName() on your new instance. - */ - LLEventPump(const std::string& name, bool tweak=false); - virtual ~LLEventPump(); - - /// group exceptions thrown by listen(). We use exceptions because these - /// particular errors are likely to be coding errors, found and fixed by - /// the developer even before preliminary checkin. - struct ListenError: public std::runtime_error - { - ListenError(const std::string& what): std::runtime_error(what) {} - }; - /** - * exception thrown by listen(). You are attempting to register a - * listener on this LLEventPump using the same listener name as an - * already-registered listener. - */ - struct DupListenerName: public ListenError - { - DupListenerName(const std::string& what): - ListenError(std::string("DupListenerName: ") + what) - {} - }; - /** - * exception thrown by listen(). The order dependencies specified for your - * listener are incompatible with existing listeners. - * - * Consider listener "a" which specifies before "b" and "b" which - * specifies before "c". You are now attempting to register "c" before - * "a". There is no order that can satisfy all constraints. - */ - struct Cycle: public ListenError - { - Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {} - }; - /** - * exception thrown by listen(). This one means that your new listener - * would force a change to the order of previously-registered listeners, - * and we don't have a good way to implement that. - * - * Consider listeners "some", "other" and "third". "some" and "other" are - * registered earlier without specifying relative order, so "other" - * happens to be first. Now you attempt to register "third" after "some" - * and before "other". Whoops, that would require swapping "some" and - * "other", which we can't do. Instead we throw this exception. - * - * It may not be possible to change the registration order so we already - * know "third"s order requirement by the time we register the second of - * "some" and "other". A solution would be to specify that "some" must - * come before "other", or equivalently that "other" must come after - * "some". - */ - struct OrderChange: public ListenError - { - OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {} - }; - - /// used by listen() - typedef std::vector<std::string> NameList; - /// convenience placeholder for when you explicitly want to pass an empty - /// NameList - const static NameList empty; - - /// Get this LLEventPump's name - std::string getName() const { return mName; } - - /** - * Register a new listener with a unique name. Specify an optional list - * of other listener names after which this one must be called, likewise - * an optional list of other listener names before which this one must be - * called. The other listeners mentioned need not yet be registered - * themselves. listen() can throw any ListenError; see ListenError - * subclasses. - * - * The listener name must be unique among active listeners for this - * LLEventPump, else you get DupListenerName. If you don't care to invent - * a name yourself, use inventName(). (I was tempted to recognize e.g. "" - * and internally generate a distinct name for that case. But that would - * handle badly the scenario in which you want to add, remove, re-add, - * etc. the same listener: each new listen() call would necessarily - * perform a new dependency sort. Assuming you specify the same - * after/before lists each time, using inventName() when you first - * instantiate your listener, then passing the same name on each listen() - * call, allows us to optimize away the second and subsequent dependency - * sorts. - * - * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a - * listener, listen() will inspect the components of that expression. If a - * bound object matches any of several cases, the connection will - * automatically be disconnected when that object is destroyed. - * - * * You bind a <tt>boost::weak_ptr</tt>. - * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the - * referenced object would @em never be destroyed, since the @c - * shared_ptr stored in the LLEventPump would remain an outstanding - * reference. Use the weaken() function to convert your @c shared_ptr to - * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr - * will produce a compile error (@c BOOST_STATIC_ASSERT failure). - * * You bind a simple pointer or reference to an object derived from - * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION) - * * You bind a simple pointer or reference to an object derived from - * LLEventTrackable. Unlike the cases described above, though, this is - * vulnerable to a couple of cross-thread race conditions, as described - * in the LLEventTrackable documentation. - */ - template <typename LISTENER> - LLBoundListener listen(const std::string& name, const LISTENER& listener, - const NameList& after=NameList(), - const NameList& before=NameList()) - { - // Examine listener, using our listen_impl() method to make the - // actual connection. - // This is why listen() is a template. Conversion from boost::bind() - // to LLEventListener performs type erasure, so it's important to look - // at the boost::bind object itself before that happens. - return LLEventDetail::visit_and_connect(listener, - boost::bind(&LLEventPump::listen_impl, - this, - name, - _1, - after, - before)); - } - - /// Get the LLBoundListener associated with the passed name (dummy - /// LLBoundListener if not found) - virtual LLBoundListener getListener(const std::string& name) const; - /** - * Instantiate one of these to block an existing connection: - * @code - * { // in some local scope - * LLEventPump::Blocker block(someLLBoundListener); - * // code that needs the connection blocked - * } // unblock the connection again - * @endcode - */ - typedef boost::signals2::shared_connection_block Blocker; - /// Unregister a listener by name. Prefer this to - /// <tt>getListener(name).disconnect()</tt> because stopListening() also - /// forgets this name. - virtual void stopListening(const std::string& name); - /// Post an event to all listeners. The @c bool return is only meaningful - /// if the underlying leaf class is LLEventStream -- beware of relying on - /// it too much! Truthfully, we return @c bool mostly to permit chaining - /// one LLEventPump as a listener on another. - virtual bool post(const LLSD&) = 0; - /// Enable/disable: while disabled, silently ignore all post() calls - virtual void enable(bool enabled=true) { mEnabled = enabled; } - /// query - virtual bool enabled() const { return mEnabled; } - - /// Generate a distinct name for a listener -- see listen() - static std::string inventName(const std::string& pfx="listener"); - -private: - friend class LLEventPumps; - /// flush queued events - virtual void flush() {} - - virtual void reset(); - -private: - virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, - const NameList& after, - const NameList& before); - std::string mName; - -protected: - /// implement the dispatching - boost::scoped_ptr<LLStandardSignal> mSignal; - - /// valve open? - bool mEnabled; - /// Map of named listeners. This tracks the listeners that actually exist - /// at this moment. When we stopListening(), we discard the entry from - /// this map. - typedef std::map<std::string, boost::signals2::connection> ConnectionMap; - ConnectionMap mConnections; - typedef LLDependencies<std::string, float> DependencyMap; - /// Dependencies between listeners. For each listener, track the float - /// used to establish its place in mSignal's order. This caches all the - /// listeners that have ever registered; stopListening() does not discard - /// the entry from this map. This is to avoid a new dependency sort if the - /// same listener with the same dependencies keeps hopping on and off this - /// LLEventPump. - DependencyMap mDeps; -}; - -/***************************************************************************** -* LLEventStream -*****************************************************************************/ -/** - * LLEventStream is a thin wrapper around LLStandardSignal. Posting an - * event immediately calls all registered listeners. - */ -class LL_COMMON_API LLEventStream: public LLEventPump -{ -public: - LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} - virtual ~LLEventStream() {} - - /// Post an event to all listeners - virtual bool post(const LLSD& event); -}; - -/***************************************************************************** -* LLEventQueue -*****************************************************************************/ -/** - * LLEventQueue isa LLEventPump whose post() method defers calling registered - * listeners until flush() is called. - */ -class LL_COMMON_API LLEventQueue: public LLEventPump -{ -public: - LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} - virtual ~LLEventQueue() {} - - /// Post an event to all listeners - virtual bool post(const LLSD& event); - -private: - /// flush queued events - virtual void flush(); - -private: - typedef std::deque<LLSD> EventQueue; - EventQueue mEventQueue; -}; - -/***************************************************************************** -* LLReqID -*****************************************************************************/ -/** - * This class helps the implementer of a given event API to honor the - * ["reqid"] convention. By this convention, each event API stamps into its - * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if - * any, from the corresponding request. - * - * This supports an (atypical, but occasionally necessary) use case in which - * two or more asynchronous requests are multiplexed onto the same ["reply"] - * LLEventPump. Since the response events could arrive in arbitrary order, the - * caller must be able to demux them. It does so by matching the ["reqid"] - * value in each response with the ["reqid"] value in the corresponding - * request. - * - * It is the caller's responsibility to ensure distinct ["reqid"] values for - * that case. Though LLSD::UUID is guaranteed to work, it might be overkill: - * the "namespace" of unique ["reqid"] values is simply the set of requests - * specifying the same ["reply"] LLEventPump name. - * - * Making a given event API echo the request's ["reqid"] into the response is - * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a - * place to put these comments. We hope that each time a coder implements a - * new event API based on some existing one, s/he will say, "Huh, what's an - * LLReqID?" and look up this material. - * - * The hardest part about the convention is deciding where to store the - * ["reqid"] value. Ironically, LLReqID can't help with that: you must store - * an LLReqID instance in whatever storage will persist until the reply is - * sent. For example, if the request ultimately ends up using a Responder - * subclass, storing an LLReqID instance in the Responder works. - * - * @note - * The @em implementer of an event API must honor the ["reqid"] convention. - * However, the @em caller of an event API need only use it if s/he is sharing - * the same ["reply"] LLEventPump for two or more asynchronous event API - * requests. - * - * In most cases, it's far easier for the caller to instantiate a local - * LLEventStream and pass its name to the event API in question. Then it's - * perfectly reasonable not to set a ["reqid"] key in the request, ignoring - * the @c isUndefined() ["reqid"] value in the response. - */ -class LL_COMMON_API LLReqID -{ -public: - /** - * If you have the request in hand at the time you instantiate the - * LLReqID, pass that request to extract its ["reqid"]. - */ - LLReqID(const LLSD& request): - mReqid(request["reqid"]) - {} - /// If you don't yet have the request, use setFrom() later. - LLReqID() {} - - /// Extract and store the ["reqid"] value from an incoming request. - void setFrom(const LLSD& request) - { - mReqid = request["reqid"]; - } - - /// Set ["reqid"] key into a pending response LLSD object. - void stamp(LLSD& response) const; - - /// Make a whole new response LLSD object with our ["reqid"]. - LLSD makeResponse() const - { - LLSD response; - stamp(response); - return response; - } - - /// Not really sure of a use case for this accessor... - LLSD getReqID() const { return mReqid; } - -private: - LLSD mReqid; -}; - -/***************************************************************************** -* Underpinnings -*****************************************************************************/ -/** - * We originally provided a suite of overloaded - * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call - * LLEventPump::listen(...) and then pass the returned LLBoundListener to - * LLEventTrackable::track(). This was workable but error-prone: the coder - * must remember to call listenTo() rather than the more straightforward - * listen() method. - * - * Now we publish only the single canonical listen() method, so there's a - * uniform mechanism. Having a single way to do this is good, in that there's - * no question in the coder's mind which of several alternatives to choose. - * - * To support automatic connection management, we use boost::visit_each - * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to - * inspect each argument of a boost::bind expression. (Although the visit_each - * mechanism was first introduced with the original Boost.Signals library, it - * was only later documented.) - * - * Cases: - * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass - * the corresponding shared_ptr to slot_type::track(). Ideally that would be - * the object whose method we want to call, but in fact we do the same for - * any weak_ptr we might find among the bound arguments. If we're passing - * our bound method a weak_ptr to some object, wouldn't the destruction of - * that object invalidate the call? So we disconnect automatically when any - * such object is destroyed. This is the mechanism preferred by boost:: - * signals2. - * * One of the functions's arguments is a boost::shared_ptr<T>. This produces - * a compile error: the bound copy of the shared_ptr stored in the - * boost_bind object stored in the signal object would make the referenced - * T object immortal. We provide a weaken() function. Pass - * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the - * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr - * implicitly and just proceed.) - * * One of the function's arguments is a plain pointer/reference to an object - * derived from boost::enable_shared_from_this. We assume that this object - * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr - * and track that. (UNDER CONSTRUCTION) - * * One of the function's arguments is derived from LLEventTrackable. Pass - * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable - * to a couple different race conditions, as described in LLEventTrackable - * documentation. (NOTE: Now that LLEventTrackable is a typedef for - * boost::signals2::trackable, the Signals2 library handles this itself, so - * our visitor needs no special logic for this case.) - * * Any other argument type is irrelevant to automatic connection management. - */ - -namespace LLEventDetail -{ - template <typename F> - const F& unwrap(const F& f) { return f; } - - template <typename F> - const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); } - - // Most of the following is lifted from the Boost.Signals use of - // visit_each. - template<bool Cond> struct truth {}; - - /** - * boost::visit_each() Visitor, used on a template argument <tt>const F& - * f</tt> as follows (see visit_and_connect()): - * @code - * LLEventListener listener(f); - * Visitor visitor(listener); // bind listener so it can track() shared_ptrs - * using boost::visit_each; // allow unqualified visit_each() call for ADL - * visit_each(visitor, unwrap(f)); - * @endcode - */ - class Visitor - { - public: - /** - * Visitor binds a reference to LLEventListener so we can track() any - * shared_ptrs we find in the argument list. - */ - Visitor(LLEventListener& listener): - mListener(listener) - { - } - - /** - * boost::visit_each() calls this method for each component of a - * boost::bind() expression. - */ - template <typename T> - void operator()(const T& t) const - { - decode(t, 0); - } - - private: - // decode() decides between a reference wrapper and anything else - // boost::ref() variant - template<typename T> - void decode(const boost::reference_wrapper<T>& t, int) const - { -// add_if_trackable(t.get_pointer()); - } - - // decode() anything else - template<typename T> - void decode(const T& t, long) const - { - typedef truth<(boost::is_pointer<T>::value)> is_a_pointer; - maybe_get_pointer(t, is_a_pointer()); - } - - // maybe_get_pointer() decides between a pointer and a non-pointer - // plain pointer variant - template<typename T> - void maybe_get_pointer(const T& t, truth<true>) const - { -// add_if_trackable(t); - } - - // shared_ptr variant - template<typename T> - void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const - { - // If we have a shared_ptr to this object, it doesn't matter - // whether the object is derived from LLEventTrackable, so no - // further analysis of T is needed. -// mListener.track(t); - - // Make this case illegal. Passing a bound shared_ptr to - // slot_type::track() is useless, since the bound shared_ptr will - // keep the object alive anyway! Force the coder to cast to weak_ptr. - - // Trivial as it is, make the BOOST_STATIC_ASSERT() condition - // dependent on template param so the macro is only evaluated if - // this method is in fact instantiated, as described here: - // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html - - // ATTENTION: Don't bind a shared_ptr<anything> using - // LLEventPump::listen(boost::bind()). Doing so captures a copy of - // the shared_ptr, making the referenced object effectively - // immortal. Use the weaken() function, e.g.: - // somepump.listen(boost::bind(...weaken(my_shared_ptr)...)); - // This lets us automatically disconnect when the referenced - // object is destroyed. - BOOST_STATIC_ASSERT(sizeof(T) == 0); - } - - // weak_ptr variant - template<typename T> - void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const - { - // If we have a weak_ptr to this object, it doesn't matter - // whether the object is derived from LLEventTrackable, so no - // further analysis of T is needed. - mListener.track(t); -// std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n"; - } - -#if 0 - // reference to anything derived from boost::enable_shared_from_this - template <typename T> - inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct, - truth<false>) const - { - // Use the slot_type::track(shared_ptr) mechanism. Cast away - // const-ness because (in our code base anyway) it's unusual - // to find shared_ptr<const T>. - boost::enable_shared_from_this<T>& - t(const_cast<boost::enable_shared_from_this<T>&>(ct)); - std::cout << "Capturing shared_from_this()" << std::endl; - boost::shared_ptr<T> sp(t.shared_from_this()); -/*==========================================================================*| - std::cout << "Capturing weak_ptr" << std::endl; - boost::weak_ptr<T> wp(sp); -|*==========================================================================*/ - std::cout << "Tracking shared__ptr" << std::endl; - mListener.track(sp); - } -#endif - - // non-pointer variant - template<typename T> - void maybe_get_pointer(const T& t, truth<false>) const - { - // Take the address of this object, because the object itself may be - // trackable -// add_if_trackable(boost::addressof(t)); - } - -/*==========================================================================*| - // add_if_trackable() adds LLEventTrackable objects to mTrackables - inline void add_if_trackable(const LLEventTrackable* t) const - { - if (t) - { - } - } - - // pointer to anything not an LLEventTrackable subclass - inline void add_if_trackable(const void*) const - { - } - - // pointer to free function - // The following construct uses the preprocessor to generate - // add_if_trackable() overloads accepting pointer-to-function taking - // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type. -#define BOOST_PP_LOCAL_MACRO(n) \ - template <typename R \ - BOOST_PP_COMMA_IF(n) \ - BOOST_PP_ENUM_PARAMS(n, typename T)> \ - inline void \ - add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \ - { \ - } -#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY) -#include BOOST_PP_LOCAL_ITERATE() -#undef BOOST_PP_LOCAL_MACRO -#undef BOOST_PP_LOCAL_LIMITS -|*==========================================================================*/ - - /// Bind a reference to the LLEventListener to call its track() method. - LLEventListener& mListener; - }; - - /** - * Utility template function to use Visitor appropriately - * - * @param raw_listener Callable to connect, typically a boost::bind() - * expression. This will be visited by Visitor using boost::visit_each(). - * @param connect_funct Callable that will connect() @a raw_listener to an - * LLStandardSignal, returning LLBoundListener. - */ - template <typename LISTENER> - LLBoundListener visit_and_connect(const LISTENER& raw_listener, - const ConnectFunc& connect_func) - { - // Capture the listener - LLEventListener listener(raw_listener); - // Define our Visitor, binding the listener so we can call - // listener.track() if we discover any shared_ptr<Foo>. - LLEventDetail::Visitor visitor(listener); - // Allow unqualified visit_each() call for ADL - using boost::visit_each; - // Visit each component of a boost::bind() expression. Pass - // 'raw_listener', our template argument, rather than 'listener' from - // which type details have been erased. unwrap() comes from - // Boost.Signals, in case we were passed a boost::ref(). - visit_each(visitor, LLEventDetail::unwrap(raw_listener)); - // Make the connection using passed function. At present, wrapping - // this functionality into this function is a bit silly: we don't - // really need a visit_and_connect() function any more, just a visit() - // function. The definition of this function dates from when, after - // visit_each(), after establishing the connection, we had to - // postprocess the new connection with the visitor object. That's no - // longer necessary. - return connect_func(listener); - } -} // namespace LLEventDetail - -// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to -// listen() fails in Boost code trying to instantiate LLEventListener (i.e. -// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't -// specialized for boost::weak_ptr. This remedies that omission. -namespace boost -{ - template <typename T> - T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); } -} - -/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an -/// easy way to cast to the corresponding weak_ptr. -template <typename T> -boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr) -{ - return boost::weak_ptr<T>(ptr); -} - -#endif /* ! defined(LL_LLEVENTS_H) */ +/** + * @file llevents.h + * @author Kent Quirk, Nat Goodspeed + * @date 2008-09-11 + * @brief This is an implementation of the event system described at + * 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=viewergpl$ + * Copyright (c) 2008, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLEVENTS_H) +#define LL_LLEVENTS_H + +#include <string> +#include <map> +#include <set> +#include <vector> +#include <deque> +#include <stdexcept> +#if LL_WINDOWS + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) +#endif +#include <boost/signals2.hpp> +#if LL_WINDOWS + #pragma warning (pop) +#endif + +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/utility.hpp> // noncopyable +#include <boost/optional/optional.hpp> +#include <boost/visit_each.hpp> +#include <boost/ref.hpp> // reference_wrapper +#include <boost/type_traits/is_pointer.hpp> +#include <boost/function.hpp> +#include <boost/static_assert.hpp> +#include "llsd.h" +#include "llsingleton.h" +#include "lldependencies.h" + +// override this to allow binding free functions with more parameters +#ifndef LLEVENTS_LISTENER_ARITY +#define LLEVENTS_LISTENER_ARITY 10 +#endif + +// hack for testing +#ifndef testable +#define testable private +#endif + +/***************************************************************************** +* Signal and handler declarations +* Using a single handler signature means that we can have a common handler +* type, rather than needing a distinct one for each different handler. +*****************************************************************************/ + +/** + * A boost::signals Combiner that stops the first time a handler returns true + * We need this because we want to have our handlers return bool, so that + * we have the option to cause a handler to stop further processing. The + * default handler fails when the signal returns a value but has no slots. + */ +struct LLStopWhenHandled +{ + typedef bool result_type; + + template<typename InputIterator> + result_type operator()(InputIterator first, InputIterator last) const + { + for (InputIterator si = first; si != last; ++si) + { + if (*si) + { + return true; + } + } + return false; + } +}; + +/** + * We want to have a standard signature for all signals; this way, + * we can easily document a protocol for communicating across + * dlls and into scripting languages someday. + * + * We want to return a bool to indicate whether the signal has been + * handled and should NOT be passed on to other listeners. + * Return true to stop further handling of the signal, and false + * to continue. + * + * We take an LLSD because this way the contents of the signal + * are independent of the API used to communicate it. + * It is const ref because then there's low cost to pass it; + * if you only need to inspect it, it's very cheap. + * + * @internal + * The @c float template parameter indicates that we will internally use @c + * float to indicate relative listener order on a given LLStandardSignal. + * Don't worry, the @c float values are strictly internal! They are not part + * of the interface, for the excellent reason that requiring the caller to + * specify a numeric key to establish order means that the caller must know + * the universe of possible values. We use LLDependencies for that instead. + */ +typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LLStandardSignal; +/// Methods that forward listeners (e.g. constructed with +/// <tt>boost::bind()</tt>) should accept (const LLEventListener&) +typedef LLStandardSignal::slot_type LLEventListener; +/// Result of registering a listener, supports <tt>connected()</tt>, +/// <tt>disconnect()</tt> and <tt>blocked()</tt> +typedef boost::signals2::connection LLBoundListener; +/// Storing an LLBoundListener in LLTempBoundListener will disconnect the +/// referenced listener when the LLTempBoundListener instance is destroyed. +typedef boost::signals2::scoped_connection LLTempBoundListener; + +/** + * A common idiom for event-based code is to accept either a callable -- + * directly called on completion -- or the string name of an LLEventPump on + * which to post the completion event. Specifying a parameter as <tt>const + * LLListenerOrPumpName&</tt> allows either. + * + * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD + * 'event' object, either calls the callable or posts the event to the named + * LLEventPump. + * + * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as + * the default value of an optional method parameter.) Calling it throws + * LLListenerOrPumpName::Empty. Test for this condition beforehand using + * either <tt>if (param)</tt> or <tt>if (! param)</tt>. + */ +class LL_COMMON_API LLListenerOrPumpName +{ +public: + /// passing string name of LLEventPump + LLListenerOrPumpName(const std::string& pumpname); + /// passing string literal (overload so compiler isn't forced to infer + /// double conversion) + LLListenerOrPumpName(const char* pumpname); + /// passing listener -- the "anything else" catch-all case. The type of an + /// object constructed by boost::bind() isn't intended to be written out. + /// Normally we'd just accept 'const LLEventListener&', but that would + /// require double implicit conversion: boost::bind() object to + /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a + /// template to forward anything. + template<typename T> + LLListenerOrPumpName(const T& listener): mListener(listener) {} + + /// for omitted method parameter: uninitialized mListener + LLListenerOrPumpName() {} + + /// test for validity + operator bool() const { return bool(mListener); } + bool operator! () const { return ! mListener; } + + /// explicit accessor + const LLEventListener& getListener() const { return *mListener; } + + /// implicit conversion to LLEventListener + operator LLEventListener() const { return *mListener; } + + /// allow calling directly + bool operator()(const LLSD& event) const; + + /// exception if you try to call when empty + struct Empty: public std::runtime_error + { + Empty(const std::string& what): + std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {} + }; + +private: + boost::optional<LLEventListener> mListener; +}; + +/***************************************************************************** +* LLEventPumps +*****************************************************************************/ +class LLEventPump; + +/** + * LLEventPumps is a Singleton manager through which one typically accesses + * this subsystem. + */ +class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps> +{ + friend class LLSingleton<LLEventPumps>; +public: + /** + * Find or create an LLEventPump instance with a specific name. We return + * a reference so there's no question about ownership. obtain() @em finds + * an instance without conferring @em ownership. + */ + LLEventPump& obtain(const std::string& name); + /** + * Flush all known LLEventPump instances + */ + void flush(); + + /** + * Reset all known LLEventPump instances + * workaround for DEV-35406 crash on shutdown + */ + void reset(); + +private: + friend class LLEventPump; + /** + * Register a new LLEventPump instance (internal) + */ + std::string registerNew(const LLEventPump&, const std::string& name, bool tweak); + /** + * Unregister a doomed LLEventPump instance (internal) + */ + void unregister(const LLEventPump&); + +private: + LLEventPumps(); + ~LLEventPumps(); + +testable: + // Map of all known LLEventPump instances, whether or not we instantiated + // them. We store a plain old LLEventPump* because this map doesn't claim + // ownership of the instances. Though the common usage pattern is to + // request an instance using obtain(), it's fair to instantiate an + // LLEventPump subclass statically, as a class member, on the stack or on + // the heap. In such cases, the instantiating party is responsible for its + // lifespan. + typedef std::map<std::string, LLEventPump*> PumpMap; + PumpMap mPumpMap; + // Set of all LLEventPumps we instantiated. Membership in this set means + // we claim ownership, and will delete them when this LLEventPumps is + // destroyed. + typedef std::set<LLEventPump*> PumpSet; + PumpSet mOurPumps; + // LLEventPump names that should be instantiated as LLEventQueue rather + // than as LLEventStream + typedef std::set<std::string> PumpNames; + PumpNames mQueueNames; +}; + +/***************************************************************************** +* details +*****************************************************************************/ +namespace LLEventDetail +{ + /// Any callable capable of connecting an LLEventListener to an + /// LLStandardSignal to produce an LLBoundListener can be mapped to this + /// signature. + typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc; + + /** + * Utility template function to use Visitor appropriately + * + * @param listener Callable to connect, typically a boost::bind() + * expression. This will be visited by Visitor using boost::visit_each(). + * @param connect_func Callable that will connect() @a listener to an + * LLStandardSignal, returning LLBoundListener. + */ + template <typename LISTENER> + LLBoundListener visit_and_connect(const LISTENER& listener, + const ConnectFunc& connect_func); +} // namespace LLEventDetail + +/***************************************************************************** +* LLEventTrackable +*****************************************************************************/ +/** + * LLEventTrackable wraps boost::signals2::trackable, which resembles + * boost::trackable. Derive your listener class from LLEventTrackable instead, + * and use something like + * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method, + * instance, _1))</tt>. This will implicitly disconnect when the object + * referenced by @c instance is destroyed. + * + * @note + * LLEventTrackable doesn't address a couple of cases: + * * Object destroyed during call + * - You enter a slot call in thread A. + * - Thread B destroys the object, which of course disconnects it from any + * future slot calls. + * - Thread A's call uses 'this', which now refers to a defunct object. + * Undefined behavior results. + * * Call during destruction + * - @c MySubclass is derived from LLEventTrackable. + * - @c MySubclass registers one of its own methods using + * <tt>LLEventPump::listen()</tt>. + * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt> + * runs, destroying state specific to the subclass. (For instance, a + * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.) + * - The listening method will not be disconnected until + * <tt>~LLEventTrackable()</tt> runs. + * - Before we get there, another thread posts data to the @c LLEventPump + * instance, calling the @c MySubclass method. + * - The method in question relies on valid @c MySubclass state. (For + * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was + * <tt>delete</tt>d but not zeroed.) + * - Undefined behavior results. + * If you suspect you may encounter any such scenario, you're better off + * managing the lifespan of your object with <tt>boost::shared_ptr</tt>. + * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression + * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging + * thread-safe Boost.Signals2 machinery. + */ +typedef boost::signals2::trackable LLEventTrackable; + +/***************************************************************************** +* LLEventPump +*****************************************************************************/ +/** + * LLEventPump is the base class interface through which we access the + * concrete subclasses LLEventStream and LLEventQueue. + * + * @NOTE + * LLEventPump derives from LLEventTrackable so that when you "chain" + * LLEventPump instances together, they will automatically disconnect on + * destruction. Please see LLEventTrackable documentation for situations in + * which this may be perilous across threads. + */ +class LL_COMMON_API LLEventPump: public LLEventTrackable +{ +public: + /** + * Exception thrown by LLEventPump(). You are trying to instantiate an + * LLEventPump (subclass) using the same name as some other instance, and + * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique + * variant. + */ + struct DupPumpName: public std::runtime_error + { + DupPumpName(const std::string& what): + std::runtime_error(std::string("DupPumpName: ") + what) {} + }; + + /** + * Instantiate an LLEventPump (subclass) with the string name by which it + * can be found using LLEventPumps::obtain(). + * + * If you pass (or default) @a tweak to @c false, then a duplicate name + * will throw DupPumpName. This won't happen if LLEventPumps::obtain() + * instantiates the LLEventPump, because obtain() uses find-or-create + * logic. It can only happen if you instantiate an LLEventPump in your own + * code -- and a collision with the name of some other LLEventPump is + * likely to cause much more subtle problems! + * + * When you hand-instantiate an LLEventPump, consider passing @a tweak as + * @c true. This directs LLEventPump() to append a suffix to the passed @a + * name to make it unique. You can retrieve the adjusted name by calling + * getName() on your new instance. + */ + LLEventPump(const std::string& name, bool tweak=false); + virtual ~LLEventPump(); + + /// group exceptions thrown by listen(). We use exceptions because these + /// particular errors are likely to be coding errors, found and fixed by + /// the developer even before preliminary checkin. + struct ListenError: public std::runtime_error + { + ListenError(const std::string& what): std::runtime_error(what) {} + }; + /** + * exception thrown by listen(). You are attempting to register a + * listener on this LLEventPump using the same listener name as an + * already-registered listener. + */ + struct DupListenerName: public ListenError + { + DupListenerName(const std::string& what): + ListenError(std::string("DupListenerName: ") + what) + {} + }; + /** + * exception thrown by listen(). The order dependencies specified for your + * listener are incompatible with existing listeners. + * + * Consider listener "a" which specifies before "b" and "b" which + * specifies before "c". You are now attempting to register "c" before + * "a". There is no order that can satisfy all constraints. + */ + struct Cycle: public ListenError + { + Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {} + }; + /** + * exception thrown by listen(). This one means that your new listener + * would force a change to the order of previously-registered listeners, + * and we don't have a good way to implement that. + * + * Consider listeners "some", "other" and "third". "some" and "other" are + * registered earlier without specifying relative order, so "other" + * happens to be first. Now you attempt to register "third" after "some" + * and before "other". Whoops, that would require swapping "some" and + * "other", which we can't do. Instead we throw this exception. + * + * It may not be possible to change the registration order so we already + * know "third"s order requirement by the time we register the second of + * "some" and "other". A solution would be to specify that "some" must + * come before "other", or equivalently that "other" must come after + * "some". + */ + struct OrderChange: public ListenError + { + OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {} + }; + + /// used by listen() + typedef std::vector<std::string> NameList; + /// convenience placeholder for when you explicitly want to pass an empty + /// NameList + const static NameList empty; + + /// Get this LLEventPump's name + std::string getName() const { return mName; } + + /** + * Register a new listener with a unique name. Specify an optional list + * of other listener names after which this one must be called, likewise + * an optional list of other listener names before which this one must be + * called. The other listeners mentioned need not yet be registered + * themselves. listen() can throw any ListenError; see ListenError + * subclasses. + * + * The listener name must be unique among active listeners for this + * LLEventPump, else you get DupListenerName. If you don't care to invent + * a name yourself, use inventName(). (I was tempted to recognize e.g. "" + * and internally generate a distinct name for that case. But that would + * handle badly the scenario in which you want to add, remove, re-add, + * etc. the same listener: each new listen() call would necessarily + * perform a new dependency sort. Assuming you specify the same + * after/before lists each time, using inventName() when you first + * instantiate your listener, then passing the same name on each listen() + * call, allows us to optimize away the second and subsequent dependency + * sorts. + * + * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a + * listener, listen() will inspect the components of that expression. If a + * bound object matches any of several cases, the connection will + * automatically be disconnected when that object is destroyed. + * + * * You bind a <tt>boost::weak_ptr</tt>. + * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the + * referenced object would @em never be destroyed, since the @c + * shared_ptr stored in the LLEventPump would remain an outstanding + * reference. Use the weaken() function to convert your @c shared_ptr to + * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr + * will produce a compile error (@c BOOST_STATIC_ASSERT failure). + * * You bind a simple pointer or reference to an object derived from + * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION) + * * You bind a simple pointer or reference to an object derived from + * LLEventTrackable. Unlike the cases described above, though, this is + * vulnerable to a couple of cross-thread race conditions, as described + * in the LLEventTrackable documentation. + */ + template <typename LISTENER> + LLBoundListener listen(const std::string& name, const LISTENER& listener, + const NameList& after=NameList(), + const NameList& before=NameList()) + { + // Examine listener, using our listen_impl() method to make the + // actual connection. + // This is why listen() is a template. Conversion from boost::bind() + // to LLEventListener performs type erasure, so it's important to look + // at the boost::bind object itself before that happens. + return LLEventDetail::visit_and_connect(listener, + boost::bind(&LLEventPump::listen_impl, + this, + name, + _1, + after, + before)); + } + + /// Get the LLBoundListener associated with the passed name (dummy + /// LLBoundListener if not found) + virtual LLBoundListener getListener(const std::string& name) const; + /** + * Instantiate one of these to block an existing connection: + * @code + * { // in some local scope + * LLEventPump::Blocker block(someLLBoundListener); + * // code that needs the connection blocked + * } // unblock the connection again + * @endcode + */ + typedef boost::signals2::shared_connection_block Blocker; + /// Unregister a listener by name. Prefer this to + /// <tt>getListener(name).disconnect()</tt> because stopListening() also + /// forgets this name. + virtual void stopListening(const std::string& name); + /// Post an event to all listeners. The @c bool return is only meaningful + /// if the underlying leaf class is LLEventStream -- beware of relying on + /// it too much! Truthfully, we return @c bool mostly to permit chaining + /// one LLEventPump as a listener on another. + virtual bool post(const LLSD&) = 0; + /// Enable/disable: while disabled, silently ignore all post() calls + virtual void enable(bool enabled=true) { mEnabled = enabled; } + /// query + virtual bool enabled() const { return mEnabled; } + + /// Generate a distinct name for a listener -- see listen() + static std::string inventName(const std::string& pfx="listener"); + +private: + friend class LLEventPumps; + /// flush queued events + virtual void flush() {} + + virtual void reset(); + +private: + virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, + const NameList& after, + const NameList& before); + std::string mName; + +protected: + /// implement the dispatching + boost::scoped_ptr<LLStandardSignal> mSignal; + + /// valve open? + bool mEnabled; + /// Map of named listeners. This tracks the listeners that actually exist + /// at this moment. When we stopListening(), we discard the entry from + /// this map. + typedef std::map<std::string, boost::signals2::connection> ConnectionMap; + ConnectionMap mConnections; + typedef LLDependencies<std::string, float> DependencyMap; + /// Dependencies between listeners. For each listener, track the float + /// used to establish its place in mSignal's order. This caches all the + /// listeners that have ever registered; stopListening() does not discard + /// the entry from this map. This is to avoid a new dependency sort if the + /// same listener with the same dependencies keeps hopping on and off this + /// LLEventPump. + DependencyMap mDeps; +}; + +/***************************************************************************** +* LLEventStream +*****************************************************************************/ +/** + * LLEventStream is a thin wrapper around LLStandardSignal. Posting an + * event immediately calls all registered listeners. + */ +class LL_COMMON_API LLEventStream: public LLEventPump +{ +public: + LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} + virtual ~LLEventStream() {} + + /// Post an event to all listeners + virtual bool post(const LLSD& event); +}; + +/***************************************************************************** +* LLEventQueue +*****************************************************************************/ +/** + * LLEventQueue isa LLEventPump whose post() method defers calling registered + * listeners until flush() is called. + */ +class LL_COMMON_API LLEventQueue: public LLEventPump +{ +public: + LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} + virtual ~LLEventQueue() {} + + /// Post an event to all listeners + virtual bool post(const LLSD& event); + +private: + /// flush queued events + virtual void flush(); + +private: + typedef std::deque<LLSD> EventQueue; + EventQueue mEventQueue; +}; + +/***************************************************************************** +* LLReqID +*****************************************************************************/ +/** + * This class helps the implementer of a given event API to honor the + * ["reqid"] convention. By this convention, each event API stamps into its + * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if + * any, from the corresponding request. + * + * This supports an (atypical, but occasionally necessary) use case in which + * two or more asynchronous requests are multiplexed onto the same ["reply"] + * LLEventPump. Since the response events could arrive in arbitrary order, the + * caller must be able to demux them. It does so by matching the ["reqid"] + * value in each response with the ["reqid"] value in the corresponding + * request. + * + * It is the caller's responsibility to ensure distinct ["reqid"] values for + * that case. Though LLSD::UUID is guaranteed to work, it might be overkill: + * the "namespace" of unique ["reqid"] values is simply the set of requests + * specifying the same ["reply"] LLEventPump name. + * + * Making a given event API echo the request's ["reqid"] into the response is + * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a + * place to put these comments. We hope that each time a coder implements a + * new event API based on some existing one, s/he will say, "Huh, what's an + * LLReqID?" and look up this material. + * + * The hardest part about the convention is deciding where to store the + * ["reqid"] value. Ironically, LLReqID can't help with that: you must store + * an LLReqID instance in whatever storage will persist until the reply is + * sent. For example, if the request ultimately ends up using a Responder + * subclass, storing an LLReqID instance in the Responder works. + * + * @note + * The @em implementer of an event API must honor the ["reqid"] convention. + * However, the @em caller of an event API need only use it if s/he is sharing + * the same ["reply"] LLEventPump for two or more asynchronous event API + * requests. + * + * In most cases, it's far easier for the caller to instantiate a local + * LLEventStream and pass its name to the event API in question. Then it's + * perfectly reasonable not to set a ["reqid"] key in the request, ignoring + * the @c isUndefined() ["reqid"] value in the response. + */ +class LL_COMMON_API LLReqID +{ +public: + /** + * If you have the request in hand at the time you instantiate the + * LLReqID, pass that request to extract its ["reqid"]. + */ + LLReqID(const LLSD& request): + mReqid(request["reqid"]) + {} + /// If you don't yet have the request, use setFrom() later. + LLReqID() {} + + /// Extract and store the ["reqid"] value from an incoming request. + void setFrom(const LLSD& request) + { + mReqid = request["reqid"]; + } + + /// Set ["reqid"] key into a pending response LLSD object. + void stamp(LLSD& response) const; + + /// Make a whole new response LLSD object with our ["reqid"]. + LLSD makeResponse() const + { + LLSD response; + stamp(response); + return response; + } + + /// Not really sure of a use case for this accessor... + LLSD getReqID() const { return mReqid; } + +private: + LLSD mReqid; +}; + +/***************************************************************************** +* Underpinnings +*****************************************************************************/ +/** + * We originally provided a suite of overloaded + * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call + * LLEventPump::listen(...) and then pass the returned LLBoundListener to + * LLEventTrackable::track(). This was workable but error-prone: the coder + * must remember to call listenTo() rather than the more straightforward + * listen() method. + * + * Now we publish only the single canonical listen() method, so there's a + * uniform mechanism. Having a single way to do this is good, in that there's + * no question in the coder's mind which of several alternatives to choose. + * + * To support automatic connection management, we use boost::visit_each + * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to + * inspect each argument of a boost::bind expression. (Although the visit_each + * mechanism was first introduced with the original Boost.Signals library, it + * was only later documented.) + * + * Cases: + * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass + * the corresponding shared_ptr to slot_type::track(). Ideally that would be + * the object whose method we want to call, but in fact we do the same for + * any weak_ptr we might find among the bound arguments. If we're passing + * our bound method a weak_ptr to some object, wouldn't the destruction of + * that object invalidate the call? So we disconnect automatically when any + * such object is destroyed. This is the mechanism preferred by boost:: + * signals2. + * * One of the functions's arguments is a boost::shared_ptr<T>. This produces + * a compile error: the bound copy of the shared_ptr stored in the + * boost_bind object stored in the signal object would make the referenced + * T object immortal. We provide a weaken() function. Pass + * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the + * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr + * implicitly and just proceed.) + * * One of the function's arguments is a plain pointer/reference to an object + * derived from boost::enable_shared_from_this. We assume that this object + * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr + * and track that. (UNDER CONSTRUCTION) + * * One of the function's arguments is derived from LLEventTrackable. Pass + * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable + * to a couple different race conditions, as described in LLEventTrackable + * documentation. (NOTE: Now that LLEventTrackable is a typedef for + * boost::signals2::trackable, the Signals2 library handles this itself, so + * our visitor needs no special logic for this case.) + * * Any other argument type is irrelevant to automatic connection management. + */ + +namespace LLEventDetail +{ + template <typename F> + const F& unwrap(const F& f) { return f; } + + template <typename F> + const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); } + + // Most of the following is lifted from the Boost.Signals use of + // visit_each. + template<bool Cond> struct truth {}; + + /** + * boost::visit_each() Visitor, used on a template argument <tt>const F& + * f</tt> as follows (see visit_and_connect()): + * @code + * LLEventListener listener(f); + * Visitor visitor(listener); // bind listener so it can track() shared_ptrs + * using boost::visit_each; // allow unqualified visit_each() call for ADL + * visit_each(visitor, unwrap(f)); + * @endcode + */ + class Visitor + { + public: + /** + * Visitor binds a reference to LLEventListener so we can track() any + * shared_ptrs we find in the argument list. + */ + Visitor(LLEventListener& listener): + mListener(listener) + { + } + + /** + * boost::visit_each() calls this method for each component of a + * boost::bind() expression. + */ + template <typename T> + void operator()(const T& t) const + { + decode(t, 0); + } + + private: + // decode() decides between a reference wrapper and anything else + // boost::ref() variant + template<typename T> + void decode(const boost::reference_wrapper<T>& t, int) const + { +// add_if_trackable(t.get_pointer()); + } + + // decode() anything else + template<typename T> + void decode(const T& t, long) const + { + typedef truth<(boost::is_pointer<T>::value)> is_a_pointer; + maybe_get_pointer(t, is_a_pointer()); + } + + // maybe_get_pointer() decides between a pointer and a non-pointer + // plain pointer variant + template<typename T> + void maybe_get_pointer(const T& t, truth<true>) const + { +// add_if_trackable(t); + } + + // shared_ptr variant + template<typename T> + void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const + { + // If we have a shared_ptr to this object, it doesn't matter + // whether the object is derived from LLEventTrackable, so no + // further analysis of T is needed. +// mListener.track(t); + + // Make this case illegal. Passing a bound shared_ptr to + // slot_type::track() is useless, since the bound shared_ptr will + // keep the object alive anyway! Force the coder to cast to weak_ptr. + + // Trivial as it is, make the BOOST_STATIC_ASSERT() condition + // dependent on template param so the macro is only evaluated if + // this method is in fact instantiated, as described here: + // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html + + // ATTENTION: Don't bind a shared_ptr<anything> using + // LLEventPump::listen(boost::bind()). Doing so captures a copy of + // the shared_ptr, making the referenced object effectively + // immortal. Use the weaken() function, e.g.: + // somepump.listen(boost::bind(...weaken(my_shared_ptr)...)); + // This lets us automatically disconnect when the referenced + // object is destroyed. + BOOST_STATIC_ASSERT(sizeof(T) == 0); + } + + // weak_ptr variant + template<typename T> + void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const + { + // If we have a weak_ptr to this object, it doesn't matter + // whether the object is derived from LLEventTrackable, so no + // further analysis of T is needed. + mListener.track(t); +// std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n"; + } + +#if 0 + // reference to anything derived from boost::enable_shared_from_this + template <typename T> + inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct, + truth<false>) const + { + // Use the slot_type::track(shared_ptr) mechanism. Cast away + // const-ness because (in our code base anyway) it's unusual + // to find shared_ptr<const T>. + boost::enable_shared_from_this<T>& + t(const_cast<boost::enable_shared_from_this<T>&>(ct)); + std::cout << "Capturing shared_from_this()" << std::endl; + boost::shared_ptr<T> sp(t.shared_from_this()); +/*==========================================================================*| + std::cout << "Capturing weak_ptr" << std::endl; + boost::weak_ptr<T> wp(sp); +|*==========================================================================*/ + std::cout << "Tracking shared__ptr" << std::endl; + mListener.track(sp); + } +#endif + + // non-pointer variant + template<typename T> + void maybe_get_pointer(const T& t, truth<false>) const + { + // Take the address of this object, because the object itself may be + // trackable +// add_if_trackable(boost::addressof(t)); + } + +/*==========================================================================*| + // add_if_trackable() adds LLEventTrackable objects to mTrackables + inline void add_if_trackable(const LLEventTrackable* t) const + { + if (t) + { + } + } + + // pointer to anything not an LLEventTrackable subclass + inline void add_if_trackable(const void*) const + { + } + + // pointer to free function + // The following construct uses the preprocessor to generate + // add_if_trackable() overloads accepting pointer-to-function taking + // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type. +#define BOOST_PP_LOCAL_MACRO(n) \ + template <typename R \ + BOOST_PP_COMMA_IF(n) \ + BOOST_PP_ENUM_PARAMS(n, typename T)> \ + inline void \ + add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \ + { \ + } +#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY) +#include BOOST_PP_LOCAL_ITERATE() +#undef BOOST_PP_LOCAL_MACRO +#undef BOOST_PP_LOCAL_LIMITS +|*==========================================================================*/ + + /// Bind a reference to the LLEventListener to call its track() method. + LLEventListener& mListener; + }; + + /** + * Utility template function to use Visitor appropriately + * + * @param raw_listener Callable to connect, typically a boost::bind() + * expression. This will be visited by Visitor using boost::visit_each(). + * @param connect_funct Callable that will connect() @a raw_listener to an + * LLStandardSignal, returning LLBoundListener. + */ + template <typename LISTENER> + LLBoundListener visit_and_connect(const LISTENER& raw_listener, + const ConnectFunc& connect_func) + { + // Capture the listener + LLEventListener listener(raw_listener); + // Define our Visitor, binding the listener so we can call + // listener.track() if we discover any shared_ptr<Foo>. + LLEventDetail::Visitor visitor(listener); + // Allow unqualified visit_each() call for ADL + using boost::visit_each; + // Visit each component of a boost::bind() expression. Pass + // 'raw_listener', our template argument, rather than 'listener' from + // which type details have been erased. unwrap() comes from + // Boost.Signals, in case we were passed a boost::ref(). + visit_each(visitor, LLEventDetail::unwrap(raw_listener)); + // Make the connection using passed function. At present, wrapping + // this functionality into this function is a bit silly: we don't + // really need a visit_and_connect() function any more, just a visit() + // function. The definition of this function dates from when, after + // visit_each(), after establishing the connection, we had to + // postprocess the new connection with the visitor object. That's no + // longer necessary. + return connect_func(listener); + } +} // namespace LLEventDetail + +// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to +// listen() fails in Boost code trying to instantiate LLEventListener (i.e. +// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't +// specialized for boost::weak_ptr. This remedies that omission. +namespace boost +{ + template <typename T> + T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); } +} + +/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an +/// easy way to cast to the corresponding weak_ptr. +template <typename T> +boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr) +{ + return boost::weak_ptr<T>(ptr); +} + +#endif /* ! defined(LL_LLEVENTS_H) */ diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 905d736d6213a1a38f1db81e2bced96c40d1ddab..45b84ea3eaa5c353913b7bc3acfec5ddbe6bafce 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,317 +1,317 @@ -/** - * @file llfasttimer.h - * @brief Declaration of a fast timer. - * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_FASTTIMER_H -#define LL_FASTTIMER_H - -#include "llinstancetracker.h" - -#define FAST_TIMER_ON 1 - -#if LL_WINDOWS - -// shift off lower 8 bits for lower resolution but longer term timing -// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing -inline U32 get_cpu_clock_count_32() -{ - U32 ret_val; - __asm - { - _emit 0x0f - _emit 0x31 - shr eax,8 - shl edx,24 - or eax, edx - mov dword ptr [ret_val], eax - } - return ret_val; -} - -// return full timer value, still shifted by 8 bits -inline U64 get_cpu_clock_count_64() -{ - U64 ret_val; - __asm - { - _emit 0x0f - _emit 0x31 - mov eax,eax - mov edx,edx - mov dword ptr [ret_val+4], edx - mov dword ptr [ret_val], eax - } - return ret_val >> 8; -} - -#endif // LL_WINDOWS - -#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) -inline U32 get_cpu_clock_count_32() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return (U32)x >> 8; -} - -inline U32 get_cpu_clock_count_64() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return x >> 8; -} -#endif - -#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) -// -// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock -// -// Just use gettimeofday implementation for now - -inline U32 get_cpu_clock_count_32() -{ - return (U32)get_clock_count(); -} - -inline U32 get_cpu_clock_count_64() -{ - return get_clock_count(); -} -#endif - -class LLMutex; - -#include <queue> -#include "llsd.h" - - -class LL_COMMON_API LLFastTimer -{ -public: - // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances - class LL_COMMON_API NamedTimer - : public LLInstanceTracker<NamedTimer> - { - friend class DeclareTimer; - public: - ~NamedTimer(); - - enum { HISTORY_NUM = 60 }; - - const std::string& getName() const { return mName; } - NamedTimer* getParent() const { return mParent; } - void setParent(NamedTimer* parent); - S32 getDepth(); - std::string getToolTip(S32 history_index = -1); - - typedef std::vector<NamedTimer*>::const_iterator child_const_iter; - child_const_iter beginChildren(); - child_const_iter endChildren(); - std::vector<NamedTimer*>& getChildren(); - - void setCollapsed(bool collapsed) { mCollapsed = collapsed; } - bool getCollapsed() const { return mCollapsed; } - - U32 getCountAverage() const { return mCountAverage; } - U32 getCallAverage() const { return mCallAverage; } - - U32 getHistoricalCount(S32 history_index = 0) const; - U32 getHistoricalCalls(S32 history_index = 0) const; - - static NamedTimer& getRootNamedTimer(); - - struct FrameState - { - FrameState(NamedTimer* timerp); - - U32 mSelfTimeCounter; - U32 mCalls; - FrameState* mParent; // info for caller timer - FrameState* mLastCaller; // used to bootstrap tree construction - NamedTimer* mTimer; - U16 mActiveCount; // number of timers with this ID active on stack - bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame - }; - - S32 getFrameStateIndex() const { return mFrameStateIndex; } - - FrameState& getFrameState() const; - - - private: - friend class LLFastTimer; - friend class NamedTimerFactory; - - // - // methods - // - NamedTimer(const std::string& name); - // recursive call to gather total time from children - static void accumulateTimings(); - - // updates cumulative times and hierarchy, - // can be called multiple times in a frame, at any point - static void processTimes(); - - static void buildHierarchy(); - static void resetFrame(); - static void reset(); - - - // - // members - // - S32 mFrameStateIndex; - - std::string mName; - - U32 mTotalTimeCounter; - - U32 mCountAverage; - U32 mCallAverage; - - U32* mCountHistory; - U32* mCallHistory; - - // tree structure - NamedTimer* mParent; // NamedTimer of caller(parent) - std::vector<NamedTimer*> mChildren; - bool mCollapsed; // don't show children - bool mNeedsSorting; // sort children whenever child added - - }; - - // used to statically declare a new named timer - class LL_COMMON_API DeclareTimer - : public LLInstanceTracker<DeclareTimer> - { - public: - DeclareTimer(const std::string& name, bool open); - DeclareTimer(const std::string& name); - - static void updateCachedPointers(); - - // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) - operator NamedTimer::FrameState&() { return *mFrameState; } - private: - NamedTimer& mTimer; - NamedTimer::FrameState* mFrameState; - }; - - -public: - static LLMutex* sLogLock; - static std::queue<LLSD> sLogQueue; - static BOOL sLog; - static BOOL sMetricLog; - - typedef std::vector<NamedTimer::FrameState> info_list_t; - static info_list_t& getFrameStateList(); - - enum RootTimerMarker { ROOT }; - LLFastTimer(RootTimerMarker); - - LLFastTimer(NamedTimer::FrameState& timer) - : mFrameState(&timer) - { -#if FAST_TIMER_ON - NamedTimer::FrameState* frame_state = &timer; - U32 cur_time = get_cpu_clock_count_32(); - mStartSelfTime = cur_time; - mStartTotalTime = cur_time; - - frame_state->mActiveCount++; - frame_state->mCalls++; - // keep current parent as long as it is active when we are - frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); - - mLastTimer = sCurTimer; - sCurTimer = this; -#endif - } - - ~LLFastTimer() - { -#if FAST_TIMER_ON - NamedTimer::FrameState* frame_state = mFrameState; - U32 cur_time = get_cpu_clock_count_32(); - frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; - - frame_state->mActiveCount--; - LLFastTimer* last_timer = mLastTimer; - sCurTimer = last_timer; - - // store last caller to bootstrap tree creation - frame_state->mLastCaller = last_timer->mFrameState; - - // we are only tracking self time, so subtract our total time delta from parents - U32 total_time = cur_time - mStartTotalTime; - last_timer->mStartSelfTime += total_time; -#endif - } - - - // call this once a frame to reset timers - static void nextFrame(); - - // dumps current cumulative frame stats to log - // call nextFrame() to reset timers - static void dumpCurTimes(); - - // call this to reset timer hierarchy, averages, etc. - static void reset(); - - static U64 countsPerSecond(); - static S32 getLastFrameIndex() { return sLastFrameIndex; } - static S32 getCurFrameIndex() { return sCurFrameIndex; } - - static void writeLog(std::ostream& os); - static const NamedTimer* getTimerByName(const std::string& name); - -public: - static bool sPauseHistory; - static bool sResetHistory; - -private: - typedef std::vector<LLFastTimer*> timer_stack_t; - static LLFastTimer* sCurTimer; - static S32 sCurFrameIndex; - static S32 sLastFrameIndex; - static U64 sLastFrameTime; - static info_list_t* sTimerInfos; - - U32 mStartSelfTime; // start time + time of all child timers - U32 mStartTotalTime; // start time + time of all child timers - NamedTimer::FrameState* mFrameState; - LLFastTimer* mLastTimer; -}; - -#endif // LL_LLFASTTIMER_H +/** + * @file llfasttimer.h + * @brief Declaration of a fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_FASTTIMER_H +#define LL_FASTTIMER_H + +#include "llinstancetracker.h" + +#define FAST_TIMER_ON 1 + +#if LL_WINDOWS + +// shift off lower 8 bits for lower resolution but longer term timing +// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing +inline U32 get_cpu_clock_count_32() +{ + U32 ret_val; + __asm + { + _emit 0x0f + _emit 0x31 + shr eax,8 + shl edx,24 + or eax, edx + mov dword ptr [ret_val], eax + } + return ret_val; +} + +// return full timer value, still shifted by 8 bits +inline U64 get_cpu_clock_count_64() +{ + U64 ret_val; + __asm + { + _emit 0x0f + _emit 0x31 + mov eax,eax + mov edx,edx + mov dword ptr [ret_val+4], edx + mov dword ptr [ret_val], eax + } + return ret_val >> 8; +} + +#endif // LL_WINDOWS + +#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +inline U32 get_cpu_clock_count_32() +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return (U32)x >> 8; +} + +inline U32 get_cpu_clock_count_64() +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return x >> 8; +} +#endif + +#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) +// +// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock +// +// Just use gettimeofday implementation for now + +inline U32 get_cpu_clock_count_32() +{ + return (U32)get_clock_count(); +} + +inline U32 get_cpu_clock_count_64() +{ + return get_clock_count(); +} +#endif + +class LLMutex; + +#include <queue> +#include "llsd.h" + + +class LL_COMMON_API LLFastTimer +{ +public: + // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances + class LL_COMMON_API NamedTimer + : public LLInstanceTracker<NamedTimer> + { + friend class DeclareTimer; + public: + ~NamedTimer(); + + enum { HISTORY_NUM = 60 }; + + const std::string& getName() const { return mName; } + NamedTimer* getParent() const { return mParent; } + void setParent(NamedTimer* parent); + S32 getDepth(); + std::string getToolTip(S32 history_index = -1); + + typedef std::vector<NamedTimer*>::const_iterator child_const_iter; + child_const_iter beginChildren(); + child_const_iter endChildren(); + std::vector<NamedTimer*>& getChildren(); + + void setCollapsed(bool collapsed) { mCollapsed = collapsed; } + bool getCollapsed() const { return mCollapsed; } + + U32 getCountAverage() const { return mCountAverage; } + U32 getCallAverage() const { return mCallAverage; } + + U32 getHistoricalCount(S32 history_index = 0) const; + U32 getHistoricalCalls(S32 history_index = 0) const; + + static NamedTimer& getRootNamedTimer(); + + struct FrameState + { + FrameState(NamedTimer* timerp); + + U32 mSelfTimeCounter; + U32 mCalls; + FrameState* mParent; // info for caller timer + FrameState* mLastCaller; // used to bootstrap tree construction + NamedTimer* mTimer; + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + }; + + S32 getFrameStateIndex() const { return mFrameStateIndex; } + + FrameState& getFrameState() const; + + + private: + friend class LLFastTimer; + friend class NamedTimerFactory; + + // + // methods + // + NamedTimer(const std::string& name); + // recursive call to gather total time from children + static void accumulateTimings(); + + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); + + static void buildHierarchy(); + static void resetFrame(); + static void reset(); + + + // + // members + // + S32 mFrameStateIndex; + + std::string mName; + + U32 mTotalTimeCounter; + + U32 mCountAverage; + U32 mCallAverage; + + U32* mCountHistory; + U32* mCallHistory; + + // tree structure + NamedTimer* mParent; // NamedTimer of caller(parent) + std::vector<NamedTimer*> mChildren; + bool mCollapsed; // don't show children + bool mNeedsSorting; // sort children whenever child added + + }; + + // used to statically declare a new named timer + class LL_COMMON_API DeclareTimer + : public LLInstanceTracker<DeclareTimer> + { + public: + DeclareTimer(const std::string& name, bool open); + DeclareTimer(const std::string& name); + + static void updateCachedPointers(); + + // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) + operator NamedTimer::FrameState&() { return *mFrameState; } + private: + NamedTimer& mTimer; + NamedTimer::FrameState* mFrameState; + }; + + +public: + static LLMutex* sLogLock; + static std::queue<LLSD> sLogQueue; + static BOOL sLog; + static BOOL sMetricLog; + + typedef std::vector<NamedTimer::FrameState> info_list_t; + static info_list_t& getFrameStateList(); + + enum RootTimerMarker { ROOT }; + LLFastTimer(RootTimerMarker); + + LLFastTimer(NamedTimer::FrameState& timer) + : mFrameState(&timer) + { +#if FAST_TIMER_ON + NamedTimer::FrameState* frame_state = &timer; + U32 cur_time = get_cpu_clock_count_32(); + mStartSelfTime = cur_time; + mStartTotalTime = cur_time; + + frame_state->mActiveCount++; + frame_state->mCalls++; + // keep current parent as long as it is active when we are + frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); + + mLastTimer = sCurTimer; + sCurTimer = this; +#endif + } + + ~LLFastTimer() + { +#if FAST_TIMER_ON + NamedTimer::FrameState* frame_state = mFrameState; + U32 cur_time = get_cpu_clock_count_32(); + frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; + + frame_state->mActiveCount--; + LLFastTimer* last_timer = mLastTimer; + sCurTimer = last_timer; + + // store last caller to bootstrap tree creation + frame_state->mLastCaller = last_timer->mFrameState; + + // we are only tracking self time, so subtract our total time delta from parents + U32 total_time = cur_time - mStartTotalTime; + last_timer->mStartSelfTime += total_time; +#endif + } + + + // call this once a frame to reset timers + static void nextFrame(); + + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); + + // call this to reset timer hierarchy, averages, etc. + static void reset(); + + static U64 countsPerSecond(); + static S32 getLastFrameIndex() { return sLastFrameIndex; } + static S32 getCurFrameIndex() { return sCurFrameIndex; } + + static void writeLog(std::ostream& os); + static const NamedTimer* getTimerByName(const std::string& name); + +public: + static bool sPauseHistory; + static bool sResetHistory; + +private: + typedef std::vector<LLFastTimer*> timer_stack_t; + static LLFastTimer* sCurTimer; + static S32 sCurFrameIndex; + static S32 sLastFrameIndex; + static U64 sLastFrameTime; + static info_list_t* sTimerInfos; + + U32 mStartSelfTime; // start time + time of all child timers + U32 mStartTotalTime; // start time + time of all child timers + NamedTimer::FrameState* mFrameState; + LLFastTimer* mLastTimer; +}; + +#endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 09f19532b7c56439e2b580cdffd326ba9b14cf1d..1c6f64dd8bcc5ad0fb112abce920352156adca74 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -1,65 +1,65 @@ -/** - * @file llmemory.h - * @brief Memory allocation/deallocation header-stuff goes here. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#ifndef LLMEMORY_H -#define LLMEMORY_H - - - -extern S32 gTotalDAlloc; -extern S32 gTotalDAUse; -extern S32 gDACount; - -extern void* ll_allocate (size_t size); -extern void ll_release (void *p); - -class LL_COMMON_API LLMemory -{ -public: - static void initClass(); - static void cleanupClass(); - static void freeReserve(); - // Return the resident set size of the current process, in bytes. - // Return value is zero if not known. - static U64 getCurrentRSS(); -private: - static char* reserveMem; -}; - -// LLRefCount moved to llrefcount.h - -// LLPointer moved to llpointer.h - -// LLSafeHandle moved to llsafehandle.h - -// LLSingleton moved to llsingleton.h - -#endif +/** + * @file llmemory.h + * @brief Memory allocation/deallocation header-stuff goes here. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLMEMORY_H +#define LLMEMORY_H + + + +extern S32 gTotalDAlloc; +extern S32 gTotalDAUse; +extern S32 gDACount; + +extern void* ll_allocate (size_t size); +extern void ll_release (void *p); + +class LL_COMMON_API LLMemory +{ +public: + static void initClass(); + static void cleanupClass(); + static void freeReserve(); + // Return the resident set size of the current process, in bytes. + // Return value is zero if not known. + static U64 getCurrentRSS(); +private: + static char* reserveMem; +}; + +// LLRefCount moved to llrefcount.h + +// LLPointer moved to llpointer.h + +// LLSafeHandle moved to llsafehandle.h + +// LLSingleton moved to llsingleton.h + +#endif diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index 5952a3a7c5a5b69ea782a1b174aaf145db0aa774..677fad3034d033d558c3584ca1ffe6052f94689f 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -1,248 +1,248 @@ -/** - * @file llmemtype.h - * @brief Runtime memory usage debugging utilities. - * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_MEMTYPE_H -#define LL_MEMTYPE_H - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- - -#include "linden_common.h" -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// WARNING: Never commit with MEM_TRACK_MEM == 1 -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -#define MEM_TRACK_MEM (0 && LL_WINDOWS) - -#include <vector> - -#define MEM_TYPE_NEW(T) - -class LL_COMMON_API LLMemType -{ -public: - - // class we'll initialize all instances of as - // static members of MemType. Then use - // to construct any new mem type. - class LL_COMMON_API DeclareMemType - { - public: - DeclareMemType(char const * st); - ~DeclareMemType(); - - S32 mID; - char const * mName; - - // array so we can map an index ID to Name - static std::vector<char const *> mNameList; - }; - - LLMemType(DeclareMemType& dt); - ~LLMemType(); - - static char const * getNameFromID(S32 id); - - static DeclareMemType MTYPE_INIT; - static DeclareMemType MTYPE_STARTUP; - static DeclareMemType MTYPE_MAIN; - static DeclareMemType MTYPE_FRAME; - - static DeclareMemType MTYPE_GATHER_INPUT; - static DeclareMemType MTYPE_JOY_KEY; - - static DeclareMemType MTYPE_IDLE; - static DeclareMemType MTYPE_IDLE_PUMP; - static DeclareMemType MTYPE_IDLE_NETWORK; - static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; - static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; - static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; - static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; - static DeclareMemType MTYPE_IDLE_AUDIO; - - static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; - static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; - static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; - - static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; - static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; - - static DeclareMemType MTYPE_RENDER; - static DeclareMemType MTYPE_SLEEP; - - static DeclareMemType MTYPE_NETWORK; - static DeclareMemType MTYPE_PHYSICS; - static DeclareMemType MTYPE_INTERESTLIST; - - static DeclareMemType MTYPE_IMAGEBASE; - static DeclareMemType MTYPE_IMAGERAW; - static DeclareMemType MTYPE_IMAGEFORMATTED; - - static DeclareMemType MTYPE_APPFMTIMAGE; - static DeclareMemType MTYPE_APPRAWIMAGE; - static DeclareMemType MTYPE_APPAUXRAWIMAGE; - - static DeclareMemType MTYPE_DRAWABLE; - - static DeclareMemType MTYPE_OBJECT; - static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; - static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; - - static DeclareMemType MTYPE_DISPLAY; - static DeclareMemType MTYPE_DISPLAY_UPDATE; - static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; - static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; - static DeclareMemType MTYPE_DISPLAY_SWAP; - static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; - static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; - static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; - static DeclareMemType MTYPE_DISPLAY_STATE_SORT; - static DeclareMemType MTYPE_DISPLAY_SKY; - static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; - static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; - static DeclareMemType MTYPE_DISPLAY_RENDER_UI; - static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; - - static DeclareMemType MTYPE_VERTEX_DATA; - static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; - static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; - static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; - static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; - static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER; - static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; - static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; - static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; - static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; - static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; - static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; - static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; - static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; - static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; - static DeclareMemType MTYPE_VERTEX_SET_STRIDE; - static DeclareMemType MTYPE_VERTEX_SET_BUFFER; - static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; - static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; - - static DeclareMemType MTYPE_SPACE_PARTITION; - - static DeclareMemType MTYPE_PIPELINE; - static DeclareMemType MTYPE_PIPELINE_INIT; - static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; - static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; - static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; - static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; - static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; - static DeclareMemType MTYPE_PIPELINE_ADD_POOL; - static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; - static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; - static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; - static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; - static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; - static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; - static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; - static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; - static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; - static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; - static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; - static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; - static DeclareMemType MTYPE_PIPELINE_STATE_SORT; - static DeclareMemType MTYPE_PIPELINE_POST_SORT; - - static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; - static DeclareMemType MTYPE_PIPELINE_RENDER_HL; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; - static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; - static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; - static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; - static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; - static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; - static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; - - static DeclareMemType MTYPE_UPKEEP_POOLS; - - static DeclareMemType MTYPE_AVATAR; - static DeclareMemType MTYPE_AVATAR_MESH; - static DeclareMemType MTYPE_PARTICLES; - static DeclareMemType MTYPE_REGIONS; - - static DeclareMemType MTYPE_INVENTORY; - static DeclareMemType MTYPE_INVENTORY_DRAW; - static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; - static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; - static DeclareMemType MTYPE_INVENTORY_POST_BUILD; - static DeclareMemType MTYPE_INVENTORY_FROM_XML; - static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; - static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; - static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; - static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; - - static DeclareMemType MTYPE_ANIMATION; - static DeclareMemType MTYPE_VOLUME; - static DeclareMemType MTYPE_PRIMITIVE; - - static DeclareMemType MTYPE_SCRIPT; - static DeclareMemType MTYPE_SCRIPT_RUN; - static DeclareMemType MTYPE_SCRIPT_BYTECODE; - - static DeclareMemType MTYPE_IO_PUMP; - static DeclareMemType MTYPE_IO_TCP; - static DeclareMemType MTYPE_IO_BUFFER; - static DeclareMemType MTYPE_IO_HTTP_SERVER; - static DeclareMemType MTYPE_IO_SD_SERVER; - static DeclareMemType MTYPE_IO_SD_CLIENT; - static DeclareMemType MTYPE_IO_URL_REQUEST; - - static DeclareMemType MTYPE_DIRECTX_INIT; - - static DeclareMemType MTYPE_TEMP1; - static DeclareMemType MTYPE_TEMP2; - static DeclareMemType MTYPE_TEMP3; - static DeclareMemType MTYPE_TEMP4; - static DeclareMemType MTYPE_TEMP5; - static DeclareMemType MTYPE_TEMP6; - static DeclareMemType MTYPE_TEMP7; - static DeclareMemType MTYPE_TEMP8; - static DeclareMemType MTYPE_TEMP9; - - static DeclareMemType MTYPE_OTHER; // Special; used by display code - - S32 mTypeIndex; -}; - -//---------------------------------------------------------------------------- - -#endif - +/** + * @file llmemtype.h + * @brief Runtime memory usage debugging utilities. + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + * + * Copyright (c) 2005-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_MEMTYPE_H +#define LL_MEMTYPE_H + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- + +#include "linden_common.h" +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// WARNING: Never commit with MEM_TRACK_MEM == 1 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define MEM_TRACK_MEM (0 && LL_WINDOWS) + +#include <vector> + +#define MEM_TYPE_NEW(T) + +class LL_COMMON_API LLMemType +{ +public: + + // class we'll initialize all instances of as + // static members of MemType. Then use + // to construct any new mem type. + class LL_COMMON_API DeclareMemType + { + public: + DeclareMemType(char const * st); + ~DeclareMemType(); + + S32 mID; + char const * mName; + + // array so we can map an index ID to Name + static std::vector<char const *> mNameList; + }; + + LLMemType(DeclareMemType& dt); + ~LLMemType(); + + static char const * getNameFromID(S32 id); + + static DeclareMemType MTYPE_INIT; + static DeclareMemType MTYPE_STARTUP; + static DeclareMemType MTYPE_MAIN; + static DeclareMemType MTYPE_FRAME; + + static DeclareMemType MTYPE_GATHER_INPUT; + static DeclareMemType MTYPE_JOY_KEY; + + static DeclareMemType MTYPE_IDLE; + static DeclareMemType MTYPE_IDLE_PUMP; + static DeclareMemType MTYPE_IDLE_NETWORK; + static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; + static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; + static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; + static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; + static DeclareMemType MTYPE_IDLE_AUDIO; + + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; + + static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; + static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; + + static DeclareMemType MTYPE_RENDER; + static DeclareMemType MTYPE_SLEEP; + + static DeclareMemType MTYPE_NETWORK; + static DeclareMemType MTYPE_PHYSICS; + static DeclareMemType MTYPE_INTERESTLIST; + + static DeclareMemType MTYPE_IMAGEBASE; + static DeclareMemType MTYPE_IMAGERAW; + static DeclareMemType MTYPE_IMAGEFORMATTED; + + static DeclareMemType MTYPE_APPFMTIMAGE; + static DeclareMemType MTYPE_APPRAWIMAGE; + static DeclareMemType MTYPE_APPAUXRAWIMAGE; + + static DeclareMemType MTYPE_DRAWABLE; + + static DeclareMemType MTYPE_OBJECT; + static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; + static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; + + static DeclareMemType MTYPE_DISPLAY; + static DeclareMemType MTYPE_DISPLAY_UPDATE; + static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; + static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; + static DeclareMemType MTYPE_DISPLAY_SWAP; + static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; + static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; + static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; + static DeclareMemType MTYPE_DISPLAY_STATE_SORT; + static DeclareMemType MTYPE_DISPLAY_SKY; + static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; + static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; + static DeclareMemType MTYPE_DISPLAY_RENDER_UI; + static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; + + static DeclareMemType MTYPE_VERTEX_DATA; + static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; + static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; + static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; + static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; + static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER; + static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; + static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; + static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; + static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; + static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; + static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; + static DeclareMemType MTYPE_VERTEX_SET_STRIDE; + static DeclareMemType MTYPE_VERTEX_SET_BUFFER; + static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; + static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; + + static DeclareMemType MTYPE_SPACE_PARTITION; + + static DeclareMemType MTYPE_PIPELINE; + static DeclareMemType MTYPE_PIPELINE_INIT; + static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; + static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; + static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; + static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; + static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; + static DeclareMemType MTYPE_PIPELINE_ADD_POOL; + static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; + static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; + static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; + static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; + static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; + static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; + static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; + static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; + static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; + static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; + static DeclareMemType MTYPE_PIPELINE_STATE_SORT; + static DeclareMemType MTYPE_PIPELINE_POST_SORT; + + static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; + static DeclareMemType MTYPE_PIPELINE_RENDER_HL; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; + static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; + static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; + static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; + static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; + static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; + + static DeclareMemType MTYPE_UPKEEP_POOLS; + + static DeclareMemType MTYPE_AVATAR; + static DeclareMemType MTYPE_AVATAR_MESH; + static DeclareMemType MTYPE_PARTICLES; + static DeclareMemType MTYPE_REGIONS; + + static DeclareMemType MTYPE_INVENTORY; + static DeclareMemType MTYPE_INVENTORY_DRAW; + static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; + static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; + static DeclareMemType MTYPE_INVENTORY_POST_BUILD; + static DeclareMemType MTYPE_INVENTORY_FROM_XML; + static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; + static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; + static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; + static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; + + static DeclareMemType MTYPE_ANIMATION; + static DeclareMemType MTYPE_VOLUME; + static DeclareMemType MTYPE_PRIMITIVE; + + static DeclareMemType MTYPE_SCRIPT; + static DeclareMemType MTYPE_SCRIPT_RUN; + static DeclareMemType MTYPE_SCRIPT_BYTECODE; + + static DeclareMemType MTYPE_IO_PUMP; + static DeclareMemType MTYPE_IO_TCP; + static DeclareMemType MTYPE_IO_BUFFER; + static DeclareMemType MTYPE_IO_HTTP_SERVER; + static DeclareMemType MTYPE_IO_SD_SERVER; + static DeclareMemType MTYPE_IO_SD_CLIENT; + static DeclareMemType MTYPE_IO_URL_REQUEST; + + static DeclareMemType MTYPE_DIRECTX_INIT; + + static DeclareMemType MTYPE_TEMP1; + static DeclareMemType MTYPE_TEMP2; + static DeclareMemType MTYPE_TEMP3; + static DeclareMemType MTYPE_TEMP4; + static DeclareMemType MTYPE_TEMP5; + static DeclareMemType MTYPE_TEMP6; + static DeclareMemType MTYPE_TEMP7; + static DeclareMemType MTYPE_TEMP8; + static DeclareMemType MTYPE_TEMP9; + + static DeclareMemType MTYPE_OTHER; // Special; used by display code + + S32 mTypeIndex; +}; + +//---------------------------------------------------------------------------- + +#endif + diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 48baa50edbe809cd5a8c4f850966f281ea5f7955..48244480b1276e271669fbfb406db8d97d03098f 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -1,168 +1,168 @@ -/** - * @file llpreprocessor.h - * @brief This file should be included in all Linden Lab files and - * should only contain special preprocessor directives - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLPREPROCESSOR_H -#define LLPREPROCESSOR_H - -// Figure out endianness of platform -#ifdef LL_LINUX -#define __ENABLE_WSTRING -#include <endian.h> -#endif // LL_LINUX - -#if LL_SOLARIS -# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported. -# define LL_BIG_ENDIAN 1 -# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed -# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API -# endif -# include <sys/isa_defs.h> // ensure we know which end is up -#endif // LL_SOLARIS - -#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386))) -#define LL_LITTLE_ENDIAN 1 -#else -#define LL_BIG_ENDIAN 1 -#endif - -// Per-compiler switches -#ifdef __GNUC__ -#define LL_FORCE_INLINE inline __attribute__((always_inline)) -#else -#define LL_FORCE_INLINE __forceinline -#endif - -// Figure out differences between compilers -#if defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - #ifndef LL_GNUC - #define LL_GNUC 1 - #endif -#elif defined(__MSVC_VER__) || defined(_MSC_VER) - #ifndef LL_MSVC - #define LL_MSVC 1 - #endif - #if _MSC_VER < 1400 - #define LL_MSVC7 //Visual C++ 2003 or earlier - #endif -#endif - -// Deal with minor differences on Unixy OSes. -#if LL_DARWIN || LL_LINUX - // Different name, same functionality. - #define stricmp strcasecmp - #define strnicmp strncasecmp - - // Not sure why this is different, but... - #ifndef MAX_PATH - #define MAX_PATH PATH_MAX - #endif // not MAX_PATH - -#endif - - -// Static linking with apr on windows needs to be declared. -#if LL_WINDOWS && !LL_COMMON_LINK_SHARED -#ifndef APR_DECLARE_STATIC -#define APR_DECLARE_STATIC // For APR on Windows -#endif -#ifndef APU_DECLARE_STATIC -#define APU_DECLARE_STATIC // For APR util on Windows -#endif -#endif - -#if defined(LL_WINDOWS) -#define BOOST_REGEX_NO_LIB 1 -#define CURL_STATICLIB 1 -#ifndef XML_STATIC -#define XML_STATIC -#endif -#endif // LL_WINDOWS - - -// Deal with VC6 problems -#if LL_MSVC -#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. -#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. -#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. -//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. -#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function -#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" -#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" -#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden -#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file -#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. -#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) -#pragma warning( disable : 4996 ) // warning: deprecated - -// level 4 warnings that we need to disable: -#pragma warning (disable : 4100) // unreferenced formal parameter -#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) -#pragma warning (disable : 4244) // possible loss of data on conversions -#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template -#pragma warning (disable : 4512) // assignment operator could not be generated -#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) - -#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class -#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class -#endif // LL_MSVC - -#if LL_WINDOWS -#define LL_DLLEXPORT __declspec(dllexport) -#define LL_DLLIMPORT __declspec(dllimport) -#elif LL_LINUX -#define LL_DLLEXPORT __attribute__ ((visibility("default"))) -#define LL_DLLIMPORT -#else -#define LL_DLLEXPORT -#define LL_DLLIMPORT -#endif // LL_WINDOWS - -#if LL_COMMON_LINK_SHARED -// CMake automagically defines llcommon_EXPORTS only when building llcommon -// sources, and only when llcommon is a shared library (i.e. when -// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because -// otherwise we can't distinguish between (non-llcommon source) and (llcommon -// not shared). -# if defined(llcommon_EXPORTS) -# define LL_COMMON_API LL_DLLEXPORT -# else //llcommon_EXPORTS -# define LL_COMMON_API LL_DLLIMPORT -# endif //llcommon_EXPORTS -#else // LL_COMMON_LINK_SHARED -# define LL_COMMON_API -#endif // LL_COMMON_LINK_SHARED - -#endif // not LL_LINDEN_PREPROCESSOR_H +/** + * @file llpreprocessor.h + * @brief This file should be included in all Linden Lab files and + * should only contain special preprocessor directives + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLPREPROCESSOR_H +#define LLPREPROCESSOR_H + +// Figure out endianness of platform +#ifdef LL_LINUX +#define __ENABLE_WSTRING +#include <endian.h> +#endif // LL_LINUX + +#if LL_SOLARIS +# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported. +# define LL_BIG_ENDIAN 1 +# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed +# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API +# endif +# include <sys/isa_defs.h> // ensure we know which end is up +#endif // LL_SOLARIS + +#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386))) +#define LL_LITTLE_ENDIAN 1 +#else +#define LL_BIG_ENDIAN 1 +#endif + +// Per-compiler switches +#ifdef __GNUC__ +#define LL_FORCE_INLINE inline __attribute__((always_inline)) +#else +#define LL_FORCE_INLINE __forceinline +#endif + +// Figure out differences between compilers +#if defined(__GNUC__) + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + #ifndef LL_GNUC + #define LL_GNUC 1 + #endif +#elif defined(__MSVC_VER__) || defined(_MSC_VER) + #ifndef LL_MSVC + #define LL_MSVC 1 + #endif + #if _MSC_VER < 1400 + #define LL_MSVC7 //Visual C++ 2003 or earlier + #endif +#endif + +// Deal with minor differences on Unixy OSes. +#if LL_DARWIN || LL_LINUX + // Different name, same functionality. + #define stricmp strcasecmp + #define strnicmp strncasecmp + + // Not sure why this is different, but... + #ifndef MAX_PATH + #define MAX_PATH PATH_MAX + #endif // not MAX_PATH + +#endif + + +// Static linking with apr on windows needs to be declared. +#if LL_WINDOWS && !LL_COMMON_LINK_SHARED +#ifndef APR_DECLARE_STATIC +#define APR_DECLARE_STATIC // For APR on Windows +#endif +#ifndef APU_DECLARE_STATIC +#define APU_DECLARE_STATIC // For APR util on Windows +#endif +#endif + +#if defined(LL_WINDOWS) +#define BOOST_REGEX_NO_LIB 1 +#define CURL_STATICLIB 1 +#ifndef XML_STATIC +#define XML_STATIC +#endif +#endif // LL_WINDOWS + + +// Deal with VC6 problems +#if LL_MSVC +#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. +#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. +#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. +//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. +#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function +#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" +#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" +#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden +#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file +#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. +#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable : 4996 ) // warning: deprecated + +// level 4 warnings that we need to disable: +#pragma warning (disable : 4100) // unreferenced formal parameter +#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) +#pragma warning (disable : 4244) // possible loss of data on conversions +#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template +#pragma warning (disable : 4512) // assignment operator could not be generated +#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) + +#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class +#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class +#endif // LL_MSVC + +#if LL_WINDOWS +#define LL_DLLEXPORT __declspec(dllexport) +#define LL_DLLIMPORT __declspec(dllimport) +#elif LL_LINUX +#define LL_DLLEXPORT __attribute__ ((visibility("default"))) +#define LL_DLLIMPORT +#else +#define LL_DLLEXPORT +#define LL_DLLIMPORT +#endif // LL_WINDOWS + +#if LL_COMMON_LINK_SHARED +// CMake automagically defines llcommon_EXPORTS only when building llcommon +// sources, and only when llcommon is a shared library (i.e. when +// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because +// otherwise we can't distinguish between (non-llcommon source) and (llcommon +// not shared). +# if defined(llcommon_EXPORTS) +# define LL_COMMON_API LL_DLLEXPORT +# else //llcommon_EXPORTS +# define LL_COMMON_API LL_DLLIMPORT +# endif //llcommon_EXPORTS +#else // LL_COMMON_LINK_SHARED +# define LL_COMMON_API +#endif // LL_COMMON_LINK_SHARED + +#endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index 3cb074257bc8927e6f05e53c1aa3161f18707a94..6558df70a42cc4d92098f6b77507756e96155cd5 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -1,142 +1,142 @@ -/** - * @file llstacktrace.cpp - * @brief stack tracing functionality - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llstacktrace.h" - -#ifdef LL_WINDOWS - -#include <iostream> -#include <sstream> - -#include "windows.h" -#include "Dbghelp.h" - -typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( - IN ULONG frames_to_skip, - IN ULONG frames_to_capture, - OUT PVOID *backtrace, - OUT PULONG backtrace_hash); - -static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = - (RtlCaptureStackBackTrace_Function*) - GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); - -bool ll_get_stack_trace(std::vector<std::string>& lines) -{ - const S32 MAX_STACK_DEPTH = 32; - const S32 STRING_NAME_LENGTH = 200; - const S32 FRAME_SKIP = 2; - static BOOL symbolsLoaded = false; - static BOOL firstCall = true; - - HANDLE hProc = GetCurrentProcess(); - - // load the symbols if they're not loaded - if(!symbolsLoaded && firstCall) - { - symbolsLoaded = SymInitialize(hProc, NULL, true); - firstCall = false; - } - - // if loaded, get the call stack - if(symbolsLoaded) - { - // create the frames to hold the addresses - void* frames[MAX_STACK_DEPTH]; - memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); - S32 depth = 0; - - // get the addresses - depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); - - IMAGEHLP_LINE64 line; - memset(&line, 0, sizeof(IMAGEHLP_LINE64)); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - // create something to hold address info - PIMAGEHLP_SYMBOL64 pSym; - pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - pSym->MaxNameLength = STRING_NAME_LENGTH; - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - - // get address info for each address frame - // and store - for(S32 i=0; i < depth; i++) - { - std::stringstream stack_line; - BOOL ret; - - DWORD64 addr = (DWORD64)frames[i]; - ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); - if(ret) - { - stack_line << pSym->Name << " "; - } - - DWORD dummy; - ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); - if(ret) - { - std::string file_name = line.FileName; - std::string::size_type index = file_name.rfind("\\"); - stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; - } - - lines.push_back(stack_line.str()); - } - - free(pSym); - - // TODO: figure out a way to cleanup symbol loading - // Not hugely necessary, however. - //SymCleanup(hProc); - return true; - } - else - { - lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); - } - - return false; -} - -#else - -bool ll_get_stack_trace(std::vector<std::string>& lines) -{ - return false; -} - -#endif - +/** + * @file llstacktrace.cpp + * @brief stack tracing functionality + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llstacktrace.h" + +#ifdef LL_WINDOWS + +#include <iostream> +#include <sstream> + +#include "windows.h" +#include "Dbghelp.h" + +typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( + IN ULONG frames_to_skip, + IN ULONG frames_to_capture, + OUT PVOID *backtrace, + OUT PULONG backtrace_hash); + +static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = + (RtlCaptureStackBackTrace_Function*) + GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); + +bool ll_get_stack_trace(std::vector<std::string>& lines) +{ + const S32 MAX_STACK_DEPTH = 32; + const S32 STRING_NAME_LENGTH = 200; + const S32 FRAME_SKIP = 2; + static BOOL symbolsLoaded = false; + static BOOL firstCall = true; + + HANDLE hProc = GetCurrentProcess(); + + // load the symbols if they're not loaded + if(!symbolsLoaded && firstCall) + { + symbolsLoaded = SymInitialize(hProc, NULL, true); + firstCall = false; + } + + // if loaded, get the call stack + if(symbolsLoaded) + { + // create the frames to hold the addresses + void* frames[MAX_STACK_DEPTH]; + memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); + S32 depth = 0; + + // get the addresses + depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + + IMAGEHLP_LINE64 line; + memset(&line, 0, sizeof(IMAGEHLP_LINE64)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + // create something to hold address info + PIMAGEHLP_SYMBOL64 pSym; + pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + pSym->MaxNameLength = STRING_NAME_LENGTH; + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + + // get address info for each address frame + // and store + for(S32 i=0; i < depth; i++) + { + std::stringstream stack_line; + BOOL ret; + + DWORD64 addr = (DWORD64)frames[i]; + ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); + if(ret) + { + stack_line << pSym->Name << " "; + } + + DWORD dummy; + ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); + if(ret) + { + std::string file_name = line.FileName; + std::string::size_type index = file_name.rfind("\\"); + stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; + } + + lines.push_back(stack_line.str()); + } + + free(pSym); + + // TODO: figure out a way to cleanup symbol loading + // Not hugely necessary, however. + //SymCleanup(hProc); + return true; + } + else + { + lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); + } + + return false; +} + +#else + +bool ll_get_stack_trace(std::vector<std::string>& lines) +{ + return false; +} + +#endif + diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h index b84b1aa6ade73d81ad6fb642f37b46c7904fbadb..9f857f0fd3fc3bf4872340b19a28d311d0ee4af9 100644 --- a/indra/llcommon/llstacktrace.h +++ b/indra/llcommon/llstacktrace.h @@ -1,44 +1,44 @@ -/** - * @file llstacktrace.h - * @brief stack trace functions - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - - -#ifndef LL_LLSTACKTRACE_H -#define LL_LLSTACKTRACE_H - -#include "stdtypes.h" -#include <vector> -#include <string> - -LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines); - -#endif - +/** + * @file llstacktrace.h + * @brief stack trace functions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_LLSTACKTRACE_H +#define LL_LLSTACKTRACE_H + +#include "stdtypes.h" +#include <vector> +#include <string> + +LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines); + +#endif + diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index edbb007f61c852bb09154ae60241ee26b776d418..31e70e0fe4d950989d3de39ae10991f9cc5bdf38 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,1300 +1,1300 @@ -/** - * @file llstring.h - * @brief String utility functions and std::string class. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTRING_H -#define LL_LLSTRING_H - -#include <string> -#include <cstdio> -#include <locale> -#include <iomanip> -#include "llsd.h" -#include "llfasttimer.h" - -#if LL_LINUX || LL_SOLARIS -#include <wctype.h> -#include <wchar.h> -#endif - -#include <string.h> - -#if LL_SOLARIS -// stricmp and strnicmp do not exist on Solaris: -#define stricmp strcasecmp -#define strnicmp strncasecmp -#endif - -const char LL_UNKNOWN_CHAR = '?'; - -#if LL_DARWIN || LL_LINUX || LL_SOLARIS -// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) -#include <cstring> - -namespace std -{ -template<> -struct char_traits<U16> -{ - 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<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } - - static char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } - - static char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast<char_type*>(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<char_type*>(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<char_type>(__c); } - - static int_type - to_int_type(const char_type& __c) - { return static_cast<int_type>(__c); } - - static bool - eq_int_type(const int_type& __c1, const int_type& __c2) - { return __c1 == __c2; } - - static int_type - eof() { return static_cast<int_type>(EOF); } - - static int_type - not_eof(const int_type& __c) - { return (__c == eof()) ? 0 : __c; } - }; -}; -#endif - -class LL_COMMON_API LLStringOps -{ -private: - static long sPacificTimeOffset; - static long sLocalTimeOffset; - static bool sPacificDaylightTime; - static std::map<std::string, std::string> datetimeToCodes; - -public: - 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 bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } - static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } - - static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } - static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } - - static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } - static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - - static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } - static bool isDigit(llwchar a) { return iswdigit(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 S32 collate(const char* a, const char* b) { return strcoll(a, b); } - static S32 collate(const llwchar* a, const llwchar* b); - - static void setupDatetimeInfo(bool pacific_daylight_time); - 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); -}; - -/** - * @brief Return a string constructed from in without crashing if the - * pointer is NULL. - */ -LL_COMMON_API std::string ll_safe_string(const char* in); -LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); - - -// Allowing assignments from non-strings into format_map_t is apparently -// *really* error-prone, so subclass std::string with just basic c'tors. -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(); } - -private: - std::string mString; -}; - -template <class T> -class LLStringUtilBase -{ -private: - static std::string sLocale; - -public: - typedef typename std::basic_string<T>::size_type size_type; - -public: - ///////////////////////////////////////////////////////////////////////////////////////// - // Static Utility functions that operate on std::strings - - static std::basic_string<T> null; - - typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; - LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims); - LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals); - LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch); - LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions); - LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions); - LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions); - LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions); - static void setLocale (std::string inLocale) {sLocale = inLocale;}; - static std::string getLocale (void) {return sLocale;}; - - static bool isValidIndex(const std::basic_string<T>& string, size_type i) - { - return !string.empty() && (0 <= i) && (i <= string.size()); - } - - static void trimHead(std::basic_string<T>& string); - static void trimTail(std::basic_string<T>& string); - static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); } - static void truncate(std::basic_string<T>& string, size_type count); - - static void toUpper(std::basic_string<T>& string); - static void toLower(std::basic_string<T>& string); - - // True if this is the head of s. - static BOOL isHead( const std::basic_string<T>& 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 std::basic_string<T>& string, - const std::basic_string<T>& substr); - - /** - * @brief Returns true if string ends in substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool endsWith( - const std::basic_string<T>& string, - const std::basic_string<T>& substr); - - static void addCRLF(std::basic_string<T>& string); - static void removeCRLF(std::basic_string<T>& string); - - static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ); - static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement ); - static void replaceChar( std::basic_string<T>& string, T target, T replacement ); - static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ); - - static BOOL containsNonprintable(const std::basic_string<T>& string); - static void stripNonprintable(std::basic_string<T>& string); - - /** - * @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(std::basic_string<T>& string); - - // Conversion to other data types - static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value); - static BOOL convertToU8(const std::basic_string<T>& string, U8& value); - static BOOL convertToS8(const std::basic_string<T>& string, S8& value); - static BOOL convertToS16(const std::basic_string<T>& string, S16& value); - static BOOL convertToU16(const std::basic_string<T>& string, U16& value); - static BOOL convertToU32(const std::basic_string<T>& string, U32& value); - static BOOL convertToS32(const std::basic_string<T>& string, S32& value); - static BOOL convertToF32(const std::basic_string<T>& string, F32& value); - static BOOL convertToF64(const std::basic_string<T>& 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 std::basic_string<T>& lhs, const std::basic_string<T>& 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 std::basic_string<T>& lhs, const std::basic_string<T>& rhs); - - // Case sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b); - - // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b); - - // Puts compareDict() in a form appropriate for LL container classes to use for sorting. - static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& 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(std::basic_string<T>& dst, const std::basic_string<T>& 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 std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens); -}; - -template<class T> std::basic_string<T> LLStringUtilBase<T>::null; -template<class T> std::string LLStringUtilBase<T>::sLocale; - -typedef LLStringUtilBase<char> LLStringUtil; -typedef LLStringUtilBase<llwchar> LLWStringUtil; -typedef std::basic_string<llwchar> LLWString; - -//@ Use this where we want to disallow input in the form of "foo" -// This is used to catch places where english text is embedded in the code -// instead of in a translatable XUI file. -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) {} -}; - -struct LLDictionaryLess -{ -public: - bool operator()(const std::string& a, const std::string& b) - { - return (LLStringUtil::precedesDict(a, b) ? true : false); - } -}; - - -/** - * Simple support functions - */ - -/** - * @brief chop off the trailing characters in a string. - * - * This function works on bytes rather than glyphs, so this will - * incorrectly truncate non-single byte strings. - * Use utf8str_truncate() for utf8 strings - * @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) -{ - return std::string(in, 0, in.length() - count); -} - -/** - * @brief This translates a nybble stored as a hex value from 0-f back - * to a nybble in the low order bits of the return byte. - */ -LL_COMMON_API U8 hex_as_nybble(char hex); - -/** - * @brief read the contents of a file into a string. - * - * Since this function has no concept of character encoding, most - * anything you do with this method ill-advised. Please avoid. - * @param str [out] The string which will have. - * @param filename The full name of the file to read. - * @return Returns true on success. If false, str is unmodified. - */ -LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); -LL_COMMON_API bool iswindividual(llwchar elem); - -/** - * Unicode support - */ - -// Make the incoming string a utf8 string. Replaces any unknown glyph -// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest -// of the data may not be recovered. -LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); - -// -// We should never use UTF16 except when communicating with Win32! -// -typedef std::basic_string<U16> llutf16string; - -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); - -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); - -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); - -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); -// Same function, better name. JC -inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } - -// -LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); - -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); - -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); - -// Length of this UTF32 string in bytes when transformed to UTF8 -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 std::string utf8str_tolower(const std::string& utf8str); - -// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. -LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); - -// Length in utf16string (UTF-16) of wlen wchars beginning at woffset. -LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); - -// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) -LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); - -/** - * @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. - * @param utf8str A valid utf8 string to truncate. - * @param max_len The maximum number of bytes in the return value. - * @return Returns a valid utf8 string with byte count <= max_len. - */ -LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); - -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); - -/** - * @brief Replace all occurences of target_char with replace_char - * - * @param utf8str A utf8 string to process. - * @param target_char The wchar to be replaced - * @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); - -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 utf8str_removeCRLF(const std::string& utf8str); - - -#if LL_WINDOWS -/* @name Windows string helpers - */ -//@{ - -/** - * @brief Implementation the expected snprintf interface. - * - * If the size of the passed in buffer is not large enough to hold the string, - * two bad things happen: - * 1. resulting formatted string is NOT null terminated - * 2. Depending on the platform, the return value could be a) the required - * size of the buffer to copy the entire formatted string or b) -1. - * On Windows with VS.Net 2003, it returns -1 e.g. - * - * safe_snprintf always adds a NULL terminator so that the caller does not - * need to check for return value or need to add the NULL terminator. - * It does not, however change the return value - to let the caller know - * that the passed in buffer size was not large enough to hold the - * formatted string. - * - */ - -// Deal with the differeneces on Windows -namespace snprintf_hack -{ - LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); -} - -using snprintf_hack::snprintf; - -/** - * @brief Convert a wide string to std::string - * - * This replaces the unsafe W2A macro from ATL. - */ -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); - -//@} -#endif // LL_WINDOWS - -/** - * Many of the 'strip' and 'replace' methods of LLStringUtilBase need - * specialization to work with the signed char type. - * Sadly, it is not possible (AFAIK) to specialize a single method of - * a template class. - * That stuff should go here. - */ -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<char>& 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<char>& 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<char>& string, - char replacement); -} - -//////////////////////////////////////////////////////////// -// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. -// There is no LLWStringUtil::format implementation currently. -// Calling thse for anything other than LLStringUtil will produce link errors. - -//////////////////////////////////////////////////////////// - - -// static -template<class T> -S32 LLStringUtilBase<T>::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; -} - -//static -template<class T> -S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) -{ - return LLStringOps::collate(lhs.c_str(), rhs.c_str()); -} - -// static -template<class T> -S32 LLStringUtilBase<T>::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 - { - std::basic_string<T> lhs_string(lhs); - std::basic_string<T> rhs_string(rhs); - LLStringUtilBase<T>::toUpper(lhs_string); - LLStringUtilBase<T>::toUpper(rhs_string); - result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); - } - return result; -} - -//static -template<class T> -S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) -{ - std::basic_string<T> lhs_string(lhs); - std::basic_string<T> rhs_string(rhs); - LLStringUtilBase<T>::toUpper(lhs_string); - LLStringUtilBase<T>::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 -template<class T> -S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& 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( ai<bi ){ ca=0; break; } - if( bi<ai ){ cb=0; break; } - if( ca!=cb ) break; - cnt = ai; - } - }else if( ca!=cb ){ break; - } - ca = *(a++); - cb = *(b++); - } - if( ca==cb ) ca += bias; - return ca-cb; -} - -// static -template<class T> -S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& 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( ai<bi ){ ca=0; break; } - if( bi<ai ){ cb=0; break; } - if( ca!=cb ) break; - cnt = ai; - } - }else if( ca!=cb ){ break; - } - ca = *(a++); - cb = *(b++); - } - return ca-cb; -} - -// Puts compareDict() in a form appropriate for LL container classes to use for sorting. -// static -template<class T> -BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ) -{ - if( a.size() && b.size() ) - { - return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); - } - else - { - return (!b.empty()); - } -} - -//static -template<class T> -void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toUpper); - } -} - -//static -template<class T> -void LLStringUtilBase<T>::toLower(std::basic_string<T>& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toLower); - } -} - -//static -template<class T> -void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string) -{ - if( !string.empty() ) - { - size_type i = 0; - while( i < string.length() && LLStringOps::isSpace( string[i] ) ) - { - i++; - } - string.erase(0, i); - } -} - -//static -template<class T> -void LLStringUtilBase<T>::trimTail(std::basic_string<T>& 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 ); - } -} - - -// Replace line feeds with carriage return-line feed pairs. -//static -template<class T> -void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& 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); - } -} - -// Remove all carriage returns -//static -template<class T> -void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& 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); -} - -//static -template<class T> -void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement ) -{ - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) - { - string[found_pos] = replacement; - found_pos++; // avoid infinite defeat if target == replacement - } -} - -//static -template<class T> -void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ) -{ - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) - { - string.replace( found_pos, target.length(), replacement ); - found_pos += replacement.length(); // avoid infinite defeat if replacement contains target - } -} - -//static -template<class T> -void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& 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; - } - } -} - -//static -template<class T> -void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab ) -{ - const T TAB = '\t'; - const T SPACE = ' '; - - std::basic_string<T> 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<class T> -BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& 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; -} - -//static -template<class T> -void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& 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; -} - -template<class T> -void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& 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; - } - } -} - -// static -template<class T> -void LLStringUtilBase<T>::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'; - } -} - -// static -template<class T> -void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& 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 - { - std::basic_string<T> tail = dst.substr(offset); - - dst = dst.substr(0, offset); - dst += src; - dst += tail; - }; -} - -// True if this is the head of s. -//static -template<class T> -BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s ) -{ - if( string.empty() ) - { - // Early exit - return FALSE; - } - else - { - return (strncmp( s, string.c_str(), string.size() ) == 0); - } -} - -// static -template<class T> -bool LLStringUtilBase<T>::startsWith( - const std::basic_string<T>& string, - const std::basic_string<T>& substr) -{ - if(string.empty() || (substr.empty())) return false; - if(0 == string.find(substr)) return true; - return false; -} - -// static -template<class T> -bool LLStringUtilBase<T>::endsWith( - const std::basic_string<T>& string, - const std::basic_string<T>& substr) -{ - if(string.empty() || (substr.empty())) return false; - std::string::size_type idx = string.rfind(substr); - if(std::string::npos == idx) return false; - return (idx == (string.size() - substr.size())); -} - - -template<class T> -BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string<T> 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<class T> -BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& 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<class T> -BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& 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<class T> -BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& 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<class T> -BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& 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<class T> -BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string<T> temp( string ); - trim(temp); - U32 v; - std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); - if(i_stream >> v) - { - value = v; - return TRUE; - } - return FALSE; -} - -template<class T> -BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string<T> temp( string ); - trim(temp); - S32 v; - std::basic_istringstream<T> i_stream((std::basic_string<T>)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<class T> -BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& 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<class T> -BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string<T> temp( string ); - trim(temp); - F64 v; - std::basic_istringstream<T> i_stream((std::basic_string<T>)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<class T> -void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count) -{ - size_type cur_size = string.size(); - string.resize(count < cur_size ? count : cur_size); -} - -#endif // LL_STRING_H +/** + * @file llstring.h + * @brief String utility functions and std::string class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSTRING_H +#define LL_LLSTRING_H + +#include <string> +#include <cstdio> +#include <locale> +#include <iomanip> +#include "llsd.h" +#include "llfasttimer.h" + +#if LL_LINUX || LL_SOLARIS +#include <wctype.h> +#include <wchar.h> +#endif + +#include <string.h> + +#if LL_SOLARIS +// stricmp and strnicmp do not exist on Solaris: +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif + +const char LL_UNKNOWN_CHAR = '?'; + +#if LL_DARWIN || LL_LINUX || LL_SOLARIS +// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) +#include <cstring> + +namespace std +{ +template<> +struct char_traits<U16> +{ + 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<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } + + static char_type* + move(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } + + static char_type* + copy(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast<char_type*>(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<char_type*>(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<char_type>(__c); } + + static int_type + to_int_type(const char_type& __c) + { return static_cast<int_type>(__c); } + + static bool + eq_int_type(const int_type& __c1, const int_type& __c2) + { return __c1 == __c2; } + + static int_type + eof() { return static_cast<int_type>(EOF); } + + static int_type + not_eof(const int_type& __c) + { return (__c == eof()) ? 0 : __c; } + }; +}; +#endif + +class LL_COMMON_API LLStringOps +{ +private: + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; + static std::map<std::string, std::string> datetimeToCodes; + +public: + 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 bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(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 S32 collate(const char* a, const char* b) { return strcoll(a, b); } + static S32 collate(const llwchar* a, const llwchar* b); + + static void setupDatetimeInfo(bool pacific_daylight_time); + 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); +}; + +/** + * @brief Return a string constructed from in without crashing if the + * pointer is NULL. + */ +LL_COMMON_API std::string ll_safe_string(const char* in); +LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); + + +// Allowing assignments from non-strings into format_map_t is apparently +// *really* error-prone, so subclass std::string with just basic c'tors. +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(); } + +private: + std::string mString; +}; + +template <class T> +class LLStringUtilBase +{ +private: + static std::string sLocale; + +public: + typedef typename std::basic_string<T>::size_type size_type; + +public: + ///////////////////////////////////////////////////////////////////////////////////////// + // Static Utility functions that operate on std::strings + + static std::basic_string<T> null; + + typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; + LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims); + LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals); + LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch); + LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions); + static void setLocale (std::string inLocale) {sLocale = inLocale;}; + static std::string getLocale (void) {return sLocale;}; + + static bool isValidIndex(const std::basic_string<T>& string, size_type i) + { + return !string.empty() && (0 <= i) && (i <= string.size()); + } + + static void trimHead(std::basic_string<T>& string); + static void trimTail(std::basic_string<T>& string); + static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); } + static void truncate(std::basic_string<T>& string, size_type count); + + static void toUpper(std::basic_string<T>& string); + static void toLower(std::basic_string<T>& string); + + // True if this is the head of s. + static BOOL isHead( const std::basic_string<T>& 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 std::basic_string<T>& string, + const std::basic_string<T>& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr); + + static void addCRLF(std::basic_string<T>& string); + static void removeCRLF(std::basic_string<T>& string); + + static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ); + static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement ); + static void replaceChar( std::basic_string<T>& string, T target, T replacement ); + static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ); + + static BOOL containsNonprintable(const std::basic_string<T>& string); + static void stripNonprintable(std::basic_string<T>& string); + + /** + * @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(std::basic_string<T>& string); + + // Conversion to other data types + static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value); + static BOOL convertToU8(const std::basic_string<T>& string, U8& value); + static BOOL convertToS8(const std::basic_string<T>& string, S8& value); + static BOOL convertToS16(const std::basic_string<T>& string, S16& value); + static BOOL convertToU16(const std::basic_string<T>& string, U16& value); + static BOOL convertToU32(const std::basic_string<T>& string, U32& value); + static BOOL convertToS32(const std::basic_string<T>& string, S32& value); + static BOOL convertToF32(const std::basic_string<T>& string, F32& value); + static BOOL convertToF64(const std::basic_string<T>& 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 std::basic_string<T>& lhs, const std::basic_string<T>& 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 std::basic_string<T>& lhs, const std::basic_string<T>& rhs); + + // Case sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b); + + // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b); + + // Puts compareDict() in a form appropriate for LL container classes to use for sorting. + static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& 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(std::basic_string<T>& dst, const std::basic_string<T>& 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 std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens); +}; + +template<class T> std::basic_string<T> LLStringUtilBase<T>::null; +template<class T> std::string LLStringUtilBase<T>::sLocale; + +typedef LLStringUtilBase<char> LLStringUtil; +typedef LLStringUtilBase<llwchar> LLWStringUtil; +typedef std::basic_string<llwchar> LLWString; + +//@ Use this where we want to disallow input in the form of "foo" +// This is used to catch places where english text is embedded in the code +// instead of in a translatable XUI file. +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) {} +}; + +struct LLDictionaryLess +{ +public: + bool operator()(const std::string& a, const std::string& b) + { + return (LLStringUtil::precedesDict(a, b) ? true : false); + } +}; + + +/** + * Simple support functions + */ + +/** + * @brief chop off the trailing characters in a string. + * + * This function works on bytes rather than glyphs, so this will + * incorrectly truncate non-single byte strings. + * Use utf8str_truncate() for utf8 strings + * @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) +{ + return std::string(in, 0, in.length() - count); +} + +/** + * @brief This translates a nybble stored as a hex value from 0-f back + * to a nybble in the low order bits of the return byte. + */ +LL_COMMON_API U8 hex_as_nybble(char hex); + +/** + * @brief read the contents of a file into a string. + * + * Since this function has no concept of character encoding, most + * anything you do with this method ill-advised. Please avoid. + * @param str [out] The string which will have. + * @param filename The full name of the file to read. + * @return Returns true on success. If false, str is unmodified. + */ +LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); +LL_COMMON_API bool iswindividual(llwchar elem); + +/** + * Unicode support + */ + +// Make the incoming string a utf8 string. Replaces any unknown glyph +// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest +// of the data may not be recovered. +LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); + +// +// We should never use UTF16 except when communicating with Win32! +// +typedef std::basic_string<U16> llutf16string; + +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); + +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); + +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); + +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); +// Same function, better name. JC +inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } + +// +LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); + +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); + +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); + +// Length of this UTF32 string in bytes when transformed to UTF8 +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 std::string utf8str_tolower(const std::string& utf8str); + +// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. +LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); + +// Length in utf16string (UTF-16) of wlen wchars beginning at woffset. +LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); + +// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) +LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); + +/** + * @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. + * @param utf8str A valid utf8 string to truncate. + * @param max_len The maximum number of bytes in the return value. + * @return Returns a valid utf8 string with byte count <= max_len. + */ +LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); + +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); + +/** + * @brief Replace all occurences of target_char with replace_char + * + * @param utf8str A utf8 string to process. + * @param target_char The wchar to be replaced + * @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); + +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 utf8str_removeCRLF(const std::string& utf8str); + + +#if LL_WINDOWS +/* @name Windows string helpers + */ +//@{ + +/** + * @brief Implementation the expected snprintf interface. + * + * If the size of the passed in buffer is not large enough to hold the string, + * two bad things happen: + * 1. resulting formatted string is NOT null terminated + * 2. Depending on the platform, the return value could be a) the required + * size of the buffer to copy the entire formatted string or b) -1. + * On Windows with VS.Net 2003, it returns -1 e.g. + * + * safe_snprintf always adds a NULL terminator so that the caller does not + * need to check for return value or need to add the NULL terminator. + * It does not, however change the return value - to let the caller know + * that the passed in buffer size was not large enough to hold the + * formatted string. + * + */ + +// Deal with the differeneces on Windows +namespace snprintf_hack +{ + LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); +} + +using snprintf_hack::snprintf; + +/** + * @brief Convert a wide string to std::string + * + * This replaces the unsafe W2A macro from ATL. + */ +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); + +//@} +#endif // LL_WINDOWS + +/** + * Many of the 'strip' and 'replace' methods of LLStringUtilBase need + * specialization to work with the signed char type. + * Sadly, it is not possible (AFAIK) to specialize a single method of + * a template class. + * That stuff should go here. + */ +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<char>& 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<char>& 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<char>& string, + char replacement); +} + +//////////////////////////////////////////////////////////// +// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. +// There is no LLWStringUtil::format implementation currently. +// Calling thse for anything other than LLStringUtil will produce link errors. + +//////////////////////////////////////////////////////////// + + +// static +template<class T> +S32 LLStringUtilBase<T>::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; +} + +//static +template<class T> +S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) +{ + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); +} + +// static +template<class T> +S32 LLStringUtilBase<T>::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 + { + std::basic_string<T> lhs_string(lhs); + std::basic_string<T> rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); + result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + } + return result; +} + +//static +template<class T> +S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) +{ + std::basic_string<T> lhs_string(lhs); + std::basic_string<T> rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::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 +template<class T> +S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& 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( ai<bi ){ ca=0; break; } + if( bi<ai ){ cb=0; break; } + if( ca!=cb ) break; + cnt = ai; + } + }else if( ca!=cb ){ break; + } + ca = *(a++); + cb = *(b++); + } + if( ca==cb ) ca += bias; + return ca-cb; +} + +// static +template<class T> +S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& 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( ai<bi ){ ca=0; break; } + if( bi<ai ){ cb=0; break; } + if( ca!=cb ) break; + cnt = ai; + } + }else if( ca!=cb ){ break; + } + ca = *(a++); + cb = *(b++); + } + return ca-cb; +} + +// Puts compareDict() in a form appropriate for LL container classes to use for sorting. +// static +template<class T> +BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ) +{ + if( a.size() && b.size() ) + { + return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); + } + else + { + return (!b.empty()); + } +} + +//static +template<class T> +void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toUpper); + } +} + +//static +template<class T> +void LLStringUtilBase<T>::toLower(std::basic_string<T>& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toLower); + } +} + +//static +template<class T> +void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string) +{ + if( !string.empty() ) + { + size_type i = 0; + while( i < string.length() && LLStringOps::isSpace( string[i] ) ) + { + i++; + } + string.erase(0, i); + } +} + +//static +template<class T> +void LLStringUtilBase<T>::trimTail(std::basic_string<T>& 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 ); + } +} + + +// Replace line feeds with carriage return-line feed pairs. +//static +template<class T> +void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& 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); + } +} + +// Remove all carriage returns +//static +template<class T> +void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& 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); +} + +//static +template<class T> +void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) + { + string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } +} + +//static +template<class T> +void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } +} + +//static +template<class T> +void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& 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; + } + } +} + +//static +template<class T> +void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab ) +{ + const T TAB = '\t'; + const T SPACE = ' '; + + std::basic_string<T> 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<class T> +BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& 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; +} + +//static +template<class T> +void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& 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; +} + +template<class T> +void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& 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; + } + } +} + +// static +template<class T> +void LLStringUtilBase<T>::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'; + } +} + +// static +template<class T> +void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& 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 + { + std::basic_string<T> tail = dst.substr(offset); + + dst = dst.substr(0, offset); + dst += src; + dst += tail; + }; +} + +// True if this is the head of s. +//static +template<class T> +BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s ) +{ + if( string.empty() ) + { + // Early exit + return FALSE; + } + else + { + return (strncmp( s, string.c_str(), string.size() ) == 0); + } +} + +// static +template<class T> +bool LLStringUtilBase<T>::startsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr) +{ + if(string.empty() || (substr.empty())) return false; + if(0 == string.find(substr)) return true; + return false; +} + +// static +template<class T> +bool LLStringUtilBase<T>::endsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr) +{ + if(string.empty() || (substr.empty())) return false; + std::string::size_type idx = string.rfind(substr); + if(std::string::npos == idx) return false; + return (idx == (string.size() - substr.size())); +} + + +template<class T> +BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string<T> 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<class T> +BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& 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<class T> +BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& 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<class T> +BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& 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<class T> +BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& 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<class T> +BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string<T> temp( string ); + trim(temp); + U32 v; + std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); + if(i_stream >> v) + { + value = v; + return TRUE; + } + return FALSE; +} + +template<class T> +BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string<T> temp( string ); + trim(temp); + S32 v; + std::basic_istringstream<T> i_stream((std::basic_string<T>)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<class T> +BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& 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<class T> +BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string<T> temp( string ); + trim(temp); + F64 v; + std::basic_istringstream<T> i_stream((std::basic_string<T>)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<class T> +void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count) +{ + size_type cur_size = string.size(); + string.resize(count < cur_size ? count : cur_size); +} + +#endif // LL_STRING_H diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index fb6d5b29054ce58dd61177322d236c9add308e69..de927de1cd6ef6c44f1805fa9a02c5bf9967ce65 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -1,1098 +1,1098 @@ -/** - * @file media_plugin_quicktime.cpp - * @brief QuickTime plugin for LLMedia API plugin system - * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llgl.h" - -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -#if LL_QUICKTIME_ENABLED - -#if defined(LL_DARWIN) - #include <QuickTime/QuickTime.h> -#elif defined(LL_WINDOWS) - #include "MacTypes.h" - #include "QTML.h" - #include "Movies.h" - #include "QDoffscreen.h" - #include "FixMath.h" - #include "QTLoadLibraryUtils.h" -#endif - -// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginQuickTime : public MediaPluginBase -{ -public: - MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - ~MediaPluginQuickTime(); - - /* virtual */ void receiveMessage(const char *message_string); - -private: - - int mNaturalWidth; - int mNaturalHeight; - Movie mMovieHandle; - GWorldPtr mGWorldHandle; - ComponentInstance mMovieController; - int mCurVolume; - bool mMediaSizeChanging; - bool mIsLooping; - std::string mMovieTitle; - bool mReceivedTitle; - const int mMinWidth; - const int mMaxWidth; - const int mMinHeight; - const int mMaxHeight; - F64 mPlayRate; - std::string mNavigateURL; - - enum ECommand { - COMMAND_NONE, - COMMAND_STOP, - COMMAND_PLAY, - COMMAND_FAST_FORWARD, - COMMAND_FAST_REWIND, - COMMAND_PAUSE, - COMMAND_SEEK, - }; - ECommand mCommand; - - // Override this to add current time and duration to the message - /*virtual*/ void setDirty(int left, int top, int right, int bottom) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); - - message.setValueS32("left", left); - message.setValueS32("top", top); - message.setValueS32("right", right); - message.setValueS32("bottom", bottom); - - if(mMovieHandle) - { - message.setValueReal("current_time", getCurrentTime()); - message.setValueReal("duration", getDuration()); - message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle))); - } - - sendMessage(message); - } - - - static Rect rectFromSize(int width, int height) - { - Rect result; - - - result.left = 0; - result.top = 0; - result.right = width; - result.bottom = height; - - return result; - } - - Fixed getPlayRate(void) - { - Fixed result; - if(mPlayRate == 0.0f) - { - // Default to the movie's preferred rate - result = GetMoviePreferredRate(mMovieHandle); - if(result == 0) - { - // Don't return a 0 play rate, ever. - std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl; - result = X2Fix(1.0f); - } - } - else - { - result = X2Fix(mPlayRate); - } - - return result; - } - - void load( const std::string url ) - { - - if ( url.empty() ) - return; - - // Stop and unload any existing movie before starting another one. - unload(); - - setStatus(STATUS_LOADING); - - //In case std::string::c_str() makes a copy of the url data, - //make sure there is memory to hold it before allocating memory for handle. - //if fails, NewHandleClear(...) should return NULL. - const char* url_string = url.c_str() ; - Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) ); - - if ( NULL == handle || noErr != MemError() || NULL == *handle ) - { - setStatus(STATUS_ERROR); - return; - } - - BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) ); - - OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType ); - DisposeHandle( handle ); - if ( noErr != err ) - { - setStatus(STATUS_ERROR); - return; - }; - - mNavigateURL = url; - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); - message.setValue("uri", mNavigateURL); - sendMessage(message); - - // do pre-roll actions (typically fired for streaming movies but not always) - PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this ); - - Rect movie_rect = rectFromSize(mWidth, mHeight); - - // make a new movie controller - mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie ); - - // movie controller - MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this ); - - SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize ); - - // function that gets called when a frame is drawn - SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this ); - - setStatus(STATUS_LOADED); - - sizeChanged(); - }; - - bool unload() - { - // new movie and have to get title again - mReceivedTitle = false; - - if ( mMovieHandle ) - { - StopMovie( mMovieHandle ); - if ( mMovieController ) - { - MCMovieChanged( mMovieController, mMovieHandle ); - }; - }; - - if ( mMovieController ) - { - MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this ); - DisposeMovieController( mMovieController ); - mMovieController = NULL; - }; - - if ( mMovieHandle ) - { - SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this ); - DisposeMovie( mMovieHandle ); - mMovieHandle = NULL; - }; - - if ( mGWorldHandle ) - { - DisposeGWorld( mGWorldHandle ); - mGWorldHandle = NULL; - }; - - setStatus(STATUS_NONE); - - return true; - } - - bool navigateTo( const std::string url ) - { - unload(); - load( url ); - - return true; - }; - - bool sizeChanged() - { - if ( ! mMovieHandle ) - return false; - - // Check to see whether the movie's natural size has updated - { - int width, height; - getMovieNaturalSize(&width, &height); - if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight))) - { - mNaturalWidth = width; - mNaturalHeight = height; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); - message.setValue("name", mTextureSegmentName); - message.setValueS32("width", width); - message.setValueS32("height", height); - sendMessage(message); - //std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl; - } - } - - // sanitize destination size - Rect dest_rect = rectFromSize(mWidth, mHeight); - - // media depth won't change - int depth_bits = mDepth * 8; - long rowbytes = mDepth * mTextureWidth; - - GWorldPtr old_gworld_handle = mGWorldHandle; - - if(mPixels != NULL) - { - // We have pixels. Set up a GWorld pointing at the texture. - OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes); - if ( noErr != result ) - { - // TODO: unrecoverable?? throw exception? return something? - return false; - } - } - else - { - // We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally. - Rect tempRect = rectFromSize(1, 1); - OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0); - if ( noErr != result ) - { - // TODO: unrecoverable?? throw exception? return something? - return false; - } - } - - SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) ); - - // If the GWorld was already set up, delete it. - if(old_gworld_handle != NULL) - { - DisposeGWorld( old_gworld_handle ); - } - - // Set up the movie display matrix - { - // scale movie to fit rect and invert vertically to match opengl image format - MatrixRecord transform; - SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix - double scaleX = (double) mWidth / mNaturalWidth; - double scaleY = -1.0 * (double) mHeight / mNaturalHeight; - double centerX = mWidth / 2.0; - double centerY = mHeight / 2.0; - ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) ); - SetMovieMatrix( mMovieHandle, &transform ); - } - - // update movie controller - if ( mMovieController ) - { - MCSetControllerPort( mMovieController, mGWorldHandle ); - MCPositionController( mMovieController, &dest_rect, &dest_rect, - mcTopLeftMovie | mcPositionDontInvalidate ); - MCMovieChanged( mMovieController, mMovieHandle ); - } - - - // Emit event with size change so the calling app knows about it too - // TODO: - //LLMediaEvent event( this ); - //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - return true; - } - static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ) - { - Boolean result = false; - - MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; - - switch( action ) - { - // handle window resizing - case mcActionControllerSizeChanged: - // Ensure that the movie draws correctly at the new size - self->sizeChanged(); - break; - - // Block any movie controller actions that open URLs. - case mcActionLinkToURL: - case mcActionGetNextURL: - case mcActionLinkToURLExtended: - // Prevent the movie controller from handling the message - result = true; - break; - - default: - break; - }; - - return result; - }; - - static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref ) - { - MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; - - // IMPORTANT: typically, a consumer who is observing this event will set a flag - // when this event is fired then render later. Be aware that the media stream - // can change during this period - dimensions, depth, format etc. - //LLMediaEvent event( self ); -// self->updateQuickTime(); - // TODO ^^^ - - - if ( self->mWidth > 0 && self->mHeight > 0 ) - self->setDirty( 0, 0, self->mWidth, self->mHeight ); - - return noErr; - }; - - static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) - { - MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; - - // TODO: - //LLMediaEvent event( self ); - //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); - - // Send a "navigate complete" event. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); - message.setValue("uri", self->mNavigateURL); - message.setValueS32("result_code", 200); - message.setValue("result_string", "OK"); - self->sendMessage(message); - }; - - - void rewind() - { - GoToBeginningOfMovie( mMovieHandle ); - MCMovieChanged( mMovieController, mMovieHandle ); - }; - - bool processState() - { - if ( mCommand == COMMAND_PLAY ) - { - if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING || mStatus == STATUS_DONE ) - { - long state = GetMovieLoadState( mMovieHandle ); - - if ( state >= kMovieLoadStatePlaythroughOK ) - { - // if the movie is at the end (generally because it reached it naturally) - // and we play is requested, jump back to the start of the movie. - // note: this is different from having loop flag set. - if ( IsMovieDone( mMovieHandle ) ) - { - Fixed rate = X2Fix( 0.0 ); - MCDoAction( mMovieController, mcActionPlay, (void*)rate ); - rewind(); - }; - - MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); - MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); - setStatus(STATUS_PLAYING); - mCommand = COMMAND_NONE; - }; - }; - } - else - if ( mCommand == COMMAND_STOP ) - { - if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED || mStatus == STATUS_DONE ) - { - if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) - { - Fixed rate = X2Fix( 0.0 ); - MCDoAction( mMovieController, mcActionPlay, (void*)rate ); - rewind(); - - setStatus(STATUS_LOADED); - mCommand = COMMAND_NONE; - }; - }; - } - else - if ( mCommand == COMMAND_PAUSE ) - { - if ( mStatus == STATUS_PLAYING ) - { - if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) - { - Fixed rate = X2Fix( 0.0 ); - MCDoAction( mMovieController, mcActionPlay, (void*)rate ); - setStatus(STATUS_PAUSED); - mCommand = COMMAND_NONE; - }; - }; - }; - - return true; - }; - - void play(F64 rate) - { - mPlayRate = rate; - mCommand = COMMAND_PLAY; - }; - - void stop() - { - mCommand = COMMAND_STOP; - }; - - void pause() - { - mCommand = COMMAND_PAUSE; - }; - - void getMovieNaturalSize(int *movie_width, int *movie_height) - { - Rect rect; - - GetMovieNaturalBoundsRect( mMovieHandle, &rect ); - - int width = ( rect.right - rect.left ); - int height = ( rect.bottom - rect.top ); - - // make sure width and height fall in valid range - if ( width < mMinWidth ) - width = mMinWidth; - - if ( width > mMaxWidth ) - width = mMaxWidth; - - if ( height < mMinHeight ) - height = mMinHeight; - - if ( height > mMaxHeight ) - height = mMaxHeight; - - // return the new rect - *movie_width = width; - *movie_height = height; - } - - void updateQuickTime(int milliseconds) - { - if ( ! mMovieHandle ) - return; - - if ( ! mMovieController ) - return; - - // service QuickTime - // Calling it this way doesn't have good behavior on Windows... -// MoviesTask( mMovieHandle, milliseconds ); - // This was the original, but I think using both MoviesTask and MCIdle is redundant. Trying with only MCIdle. -// MoviesTask( mMovieHandle, 0 ); - - MCIdle( mMovieController ); - - if ( ! mGWorldHandle ) - return; - - if ( mMediaSizeChanging ) - return; - - // update state machine - processState(); - - // see if title arrived and if so, update member variable with contents - checkTitle(); - - // QT call to see if we are at the end - can't do with controller - if ( IsMovieDone( mMovieHandle ) ) - { - // special code for looping - need to rewind at the end of the movie - if ( mIsLooping ) - { - // go back to start - rewind(); - - if ( mMovieController ) - { - // kick off new play - MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); - - // set the volume - MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); - }; - } - else - { - if(mStatus == STATUS_PLAYING) - { - setStatus(STATUS_DONE); - } - } - } - - }; - - int getDataWidth() const - { - if ( mGWorldHandle ) - { - int depth = mDepth; - - if (depth < 1) - depth = 1; - - // ALWAYS use the row bytes from the PixMap if we have a GWorld because - // sometimes it's not the same as mMediaDepth * mMediaWidth ! - PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); - return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth; - } - else - { - // TODO : return LLMediaImplCommon::getaDataWidth(); - return 0; - } - }; - - void seek( F64 time ) - { - if ( mMovieController ) - { - TimeRecord when; - when.scale = GetMovieTimeScale( mMovieHandle ); - when.base = 0; - - // 'time' is in (floating point) seconds. The timebase time will be in 'units', where - // there are 'scale' units per second. - SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) ); - - when.value.hi = ( SInt32 )( raw_time >> 32 ); - when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) ); - - MCDoAction( mMovieController, mcActionGoToTime, &when ); - }; - }; - - F64 getLoadedDuration() - { - TimeValue duration; - if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr) - { - // If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie. - duration = GetMovieDuration( mMovieHandle ); - } - TimeValue scale = GetMovieTimeScale( mMovieHandle ); - - return (F64)duration / (F64)scale; - }; - - F64 getDuration() - { - TimeValue duration = GetMovieDuration( mMovieHandle ); - TimeValue scale = GetMovieTimeScale( mMovieHandle ); - - return (F64)duration / (F64)scale; - }; - - F64 getCurrentTime() - { - TimeValue curr_time = GetMovieTime( mMovieHandle, 0 ); - TimeValue scale = GetMovieTimeScale( mMovieHandle ); - - return (F64)curr_time / (F64)scale; - }; - - void setVolume( F64 volume ) - { - mCurVolume = (short)(volume * ( double ) 0x100 ); - - if ( mMovieController ) - { - MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); - }; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void update(int milliseconds = 0) - { - updateQuickTime(milliseconds); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void mouseDown( int x, int y ) - { - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void mouseUp( int x, int y ) - { - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void mouseMove( int x, int y ) - { - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void keyPress( unsigned char key ) - { - }; - - //////////////////////////////////////////////////////////////////////////////// - // Grab movie title into mMovieTitle - should be called repeatedly - // until it returns true since movie title takes a while to become - // available. - const bool getMovieTitle() - { - // grab meta data from movie - QTMetaDataRef media_data_ref; - OSErr result = QTCopyMovieMetaData( mMovieHandle, &media_data_ref ); - if ( noErr != result ) - return false; - - // look up "Display Name" in meta data - OSType meta_data_key = kQTMetaDataCommonKeyDisplayName; - QTMetaDataItem item = kQTMetaDataItemUninitialized; - result = QTMetaDataGetNextItem( media_data_ref, kQTMetaDataStorageFormatWildcard, - 0, kQTMetaDataKeyFormatCommon, - (const UInt8 *)&meta_data_key, - sizeof( meta_data_key ), &item ); - if ( noErr != result ) - return false; - - // find the size of the title - ByteCount size; - result = QTMetaDataGetItemValue( media_data_ref, item, NULL, 0, &size ); - if ( noErr != result || size <= 0 ) - return false; - - // allocate some space and grab it - UInt8* item_data = new UInt8( size ); - memset( item_data, 0, size * sizeof( UInt8* ) ); - result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL ); - if ( noErr != result ) - return false; - - // save it - mMovieTitle = std::string( (char* )item_data ); - - // clean up - delete [] item_data; - - return true; - }; - - // called regularly to see if title changed - void checkTitle() - { - // we did already receive title so keep checking - if ( ! mReceivedTitle ) - { - // grab title from movie meta data - if ( getMovieTitle() ) - { - // pass back to host application - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); - message.setValue("name", mMovieTitle ); - sendMessage( message ); - - // stop looking once we find a title for this movie. - // TODO: this may to be reset if movie title changes - // during playback but this is okay for now - mReceivedTitle = true; - }; - }; - }; -}; - -MediaPluginQuickTime::MediaPluginQuickTime( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data), - mMinWidth( 0 ), - mMaxWidth( 2048 ), - mMinHeight( 0 ), - mMaxHeight( 2048 ) -{ -// std::cerr << "MediaPluginQuickTime constructor" << std::endl; - - mNaturalWidth = -1; - mNaturalHeight = -1; - mMovieHandle = 0; - mGWorldHandle = 0; - mMovieController = 0; - mCurVolume = 0x99; - mMediaSizeChanging = false; - mIsLooping = false; - mMovieTitle = std::string(); - mReceivedTitle = false; - mCommand = COMMAND_NONE; - mPlayRate = 0.0f; - mStatus = STATUS_NONE; -} - -MediaPluginQuickTime::~MediaPluginQuickTime() -{ -// std::cerr << "MediaPluginQuickTime destructor" << std::endl; - - ExitMovies(); - -#ifdef LL_WINDOWS - TerminateQTML(); -// std::cerr << "QuickTime closing down" << std::endl; -#endif -} - - -void MediaPluginQuickTime::receiveMessage(const char *message_string) -{ -// std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - LLPluginMessage message_in; - - if(message_in.parse(message_string) >= 0) - { - std::string message_class = message_in.getClass(); - std::string message_name = message_in.getName(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) - { - if(message_name == "init") - { - LLPluginMessage message("base", "init_response"); - LLSD versions = LLSD::emptyMap(); - versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; - // Normally a plugin would only specify one of these two subclasses, but this is a demo... - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; - message.setValueLLSD("versions", versions); - - #ifdef LL_WINDOWS - - // QuickTime 7.6.4 has an issue (that was not present in 7.6.2) with initializing QuickTime - // according to this article: http://lists.apple.com/archives/QuickTime-API/2009/Sep/msg00097.html - // The solution presented there appears to work. - QTLoadLibrary("qtcf.dll"); - - // main initialization for QuickTime - only required on Windows - OSErr result = InitializeQTML( 0L ); - if ( result != noErr ) - { - //TODO: If no QT on Windows, this fails - respond accordingly. - } - else - { - //std::cerr << "QuickTime initialized" << std::endl; - }; - #endif - - // required for both Windows and Mac - EnterMovies(); - - std::string plugin_version = "QuickTime media plugin, QuickTime version "; - - long version = 0; - Gestalt( gestaltQuickTimeVersion, &version ); - std::ostringstream codec( "" ); - codec << std::hex << version << std::dec; - plugin_version += codec.str(); - message.setValue("plugin_version", plugin_version); - sendMessage(message); - - // Plugin gets to decide the texture parameters to use. - message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - #if defined(LL_WINDOWS) - // Values for Windows - mDepth = 3; - message.setValueU32("format", GL_RGB); - message.setValueU32("type", GL_UNSIGNED_BYTE); - - // We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even. - // Padding to a multiple of 3*32 guarantees it'll divide out properly. - message.setValueU32("padding", 32 * 3); - #else - // Values for Mac - mDepth = 4; - message.setValueU32("format", GL_BGRA_EXT); - #ifdef __BIG_ENDIAN__ - message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV ); - #else - message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8); - #endif - - // Pad texture width to a multiple of 32 bytes, to line up with cache lines. - message.setValueU32("padding", 32); - #endif - message.setValueS32("depth", mDepth); - message.setValueU32("internalformat", GL_RGB); - message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. - message.setValueBoolean("allow_downsample", true); - sendMessage(message); - } - else if(message_name == "idle") - { - // no response is necessary here. - F64 time = message_in.getValueReal("time"); - - // Convert time to milliseconds for update() - update((int)(time * 1000.0f)); - } - else if(message_name == "cleanup") - { - // TODO: clean up here - } - else if(message_name == "shm_added") - { - SharedSegmentInfo info; - info.mAddress = message_in.getValuePointer("address"); - info.mSize = (size_t)message_in.getValueS32("size"); - std::string name = message_in.getValue("name"); -// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name -// << ", size: " << info.mSize -// << ", address: " << info.mAddress -// << std::endl; - - mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); - - } - else if(message_name == "shm_remove") - { - std::string name = message_in.getValue("name"); - -// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl; - - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - if(mPixels == iter->second.mAddress) - { - // This is the currently active pixel buffer. Make sure we stop drawing to it. - mPixels = NULL; - mTextureSegmentName.clear(); - - // Make sure the movie GWorld is no longer pointed at the shared segment. - sizeChanged(); - } - mSharedSegments.erase(iter); - } - else - { -// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl; - } - - // Send the response so it can be cleaned up. - LLPluginMessage message("base", "shm_remove_response"); - message.setValue("name", name); - sendMessage(message); - } - else - { -// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - if(message_name == "size_change") - { - std::string name = message_in.getValue("name"); - S32 width = message_in.getValueS32("width"); - S32 height = message_in.getValueS32("height"); - S32 texture_width = message_in.getValueS32("texture_width"); - S32 texture_height = message_in.getValueS32("texture_height"); - - //std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); - message.setValue("name", name); - message.setValueS32("width", width); - message.setValueS32("height", height); - message.setValueS32("texture_width", texture_width); - message.setValueS32("texture_height", texture_height); - sendMessage(message); - - if(!name.empty()) - { - // Find the shared memory region with this name - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { -// std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl; -// std::cerr << "%%%% texture size is " << texture_width << " by " << texture_height << std::endl; - - mPixels = (unsigned char*)iter->second.mAddress; - mTextureSegmentName = name; - mWidth = width; - mHeight = height; - - mTextureWidth = texture_width; - mTextureHeight = texture_height; - - mMediaSizeChanging = false; - - sizeChanged(); - - update(); - }; - }; - } - else if(message_name == "load_uri") - { - std::string uri = message_in.getValue("uri"); - load( uri ); - sendStatus(); - } - else if(message_name == "mouse_event") - { - std::string event = message_in.getValue("event"); - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); - - if(event == "down") - { - mouseDown(x, y); - } - else if(event == "up") - { - mouseUp(x, y); - } - else if(event == "move") - { - mouseMove(x, y); - }; - }; - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) - { - if(message_name == "stop") - { - stop(); - } - else if(message_name == "start") - { - F64 rate = 0.0; - if(message_in.hasValue("rate")) - { - rate = message_in.getValueReal("rate"); - } - play(rate); - } - else if(message_name == "pause") - { - pause(); - } - else if(message_name == "seek") - { - F64 time = message_in.getValueReal("time"); - seek(time); - } - else if(message_name == "set_loop") - { - bool loop = message_in.getValueBoolean("loop"); - mIsLooping = loop; - } - else if(message_name == "set_volume") - { - F64 volume = message_in.getValueReal("volume"); - setVolume(volume); - } - } - else - { -// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl; - }; - }; -} - -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ - MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data); - *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage; - *plugin_user_data = (void*)self; - - return 0; -} - -#else // LL_QUICKTIME_ENABLED - -// Stubbed-out class with constructor/destructor (necessary or windows linker -// will just think its dead code and optimize it all out) -class MediaPluginQuickTime : public MediaPluginBase -{ -public: - MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - ~MediaPluginQuickTime(); - /* virtual */ void receiveMessage(const char *message_string); -}; - -MediaPluginQuickTime::MediaPluginQuickTime( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data) -{ - // no-op -} - -MediaPluginQuickTime::~MediaPluginQuickTime() -{ - // no-op -} - -void MediaPluginQuickTime::receiveMessage(const char *message_string) -{ - // no-op -} - -// We're building without quicktime enabled. Just refuse to initialize. -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ - return -1; -} - -#endif // LL_QUICKTIME_ENABLED +/** + * @file media_plugin_quicktime.cpp + * @brief QuickTime plugin for LLMedia API plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_QUICKTIME_ENABLED + +#if defined(LL_DARWIN) + #include <QuickTime/QuickTime.h> +#elif defined(LL_WINDOWS) + #include "MacTypes.h" + #include "QTML.h" + #include "Movies.h" + #include "QDoffscreen.h" + #include "FixMath.h" + #include "QTLoadLibraryUtils.h" +#endif + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginQuickTime : public MediaPluginBase +{ +public: + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginQuickTime(); + + /* virtual */ void receiveMessage(const char *message_string); + +private: + + int mNaturalWidth; + int mNaturalHeight; + Movie mMovieHandle; + GWorldPtr mGWorldHandle; + ComponentInstance mMovieController; + int mCurVolume; + bool mMediaSizeChanging; + bool mIsLooping; + std::string mMovieTitle; + bool mReceivedTitle; + const int mMinWidth; + const int mMaxWidth; + const int mMinHeight; + const int mMaxHeight; + F64 mPlayRate; + std::string mNavigateURL; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + + // Override this to add current time and duration to the message + /*virtual*/ void setDirty(int left, int top, int right, int bottom) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + if(mMovieHandle) + { + message.setValueReal("current_time", getCurrentTime()); + message.setValueReal("duration", getDuration()); + message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle))); + } + + sendMessage(message); + } + + + static Rect rectFromSize(int width, int height) + { + Rect result; + + + result.left = 0; + result.top = 0; + result.right = width; + result.bottom = height; + + return result; + } + + Fixed getPlayRate(void) + { + Fixed result; + if(mPlayRate == 0.0f) + { + // Default to the movie's preferred rate + result = GetMoviePreferredRate(mMovieHandle); + if(result == 0) + { + // Don't return a 0 play rate, ever. + std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl; + result = X2Fix(1.0f); + } + } + else + { + result = X2Fix(mPlayRate); + } + + return result; + } + + void load( const std::string url ) + { + + if ( url.empty() ) + return; + + // Stop and unload any existing movie before starting another one. + unload(); + + setStatus(STATUS_LOADING); + + //In case std::string::c_str() makes a copy of the url data, + //make sure there is memory to hold it before allocating memory for handle. + //if fails, NewHandleClear(...) should return NULL. + const char* url_string = url.c_str() ; + Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) ); + + if ( NULL == handle || noErr != MemError() || NULL == *handle ) + { + setStatus(STATUS_ERROR); + return; + } + + BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) ); + + OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType ); + DisposeHandle( handle ); + if ( noErr != err ) + { + setStatus(STATUS_ERROR); + return; + }; + + mNavigateURL = url; + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message.setValue("uri", mNavigateURL); + sendMessage(message); + + // do pre-roll actions (typically fired for streaming movies but not always) + PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this ); + + Rect movie_rect = rectFromSize(mWidth, mHeight); + + // make a new movie controller + mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie ); + + // movie controller + MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this ); + + SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize ); + + // function that gets called when a frame is drawn + SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this ); + + setStatus(STATUS_LOADED); + + sizeChanged(); + }; + + bool unload() + { + // new movie and have to get title again + mReceivedTitle = false; + + if ( mMovieHandle ) + { + StopMovie( mMovieHandle ); + if ( mMovieController ) + { + MCMovieChanged( mMovieController, mMovieHandle ); + }; + }; + + if ( mMovieController ) + { + MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this ); + DisposeMovieController( mMovieController ); + mMovieController = NULL; + }; + + if ( mMovieHandle ) + { + SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this ); + DisposeMovie( mMovieHandle ); + mMovieHandle = NULL; + }; + + if ( mGWorldHandle ) + { + DisposeGWorld( mGWorldHandle ); + mGWorldHandle = NULL; + }; + + setStatus(STATUS_NONE); + + return true; + } + + bool navigateTo( const std::string url ) + { + unload(); + load( url ); + + return true; + }; + + bool sizeChanged() + { + if ( ! mMovieHandle ) + return false; + + // Check to see whether the movie's natural size has updated + { + int width, height; + getMovieNaturalSize(&width, &height); + if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight))) + { + mNaturalWidth = width; + mNaturalHeight = height; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", width); + message.setValueS32("height", height); + sendMessage(message); + //std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl; + } + } + + // sanitize destination size + Rect dest_rect = rectFromSize(mWidth, mHeight); + + // media depth won't change + int depth_bits = mDepth * 8; + long rowbytes = mDepth * mTextureWidth; + + GWorldPtr old_gworld_handle = mGWorldHandle; + + if(mPixels != NULL) + { + // We have pixels. Set up a GWorld pointing at the texture. + OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes); + if ( noErr != result ) + { + // TODO: unrecoverable?? throw exception? return something? + return false; + } + } + else + { + // We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally. + Rect tempRect = rectFromSize(1, 1); + OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0); + if ( noErr != result ) + { + // TODO: unrecoverable?? throw exception? return something? + return false; + } + } + + SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) ); + + // If the GWorld was already set up, delete it. + if(old_gworld_handle != NULL) + { + DisposeGWorld( old_gworld_handle ); + } + + // Set up the movie display matrix + { + // scale movie to fit rect and invert vertically to match opengl image format + MatrixRecord transform; + SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix + double scaleX = (double) mWidth / mNaturalWidth; + double scaleY = -1.0 * (double) mHeight / mNaturalHeight; + double centerX = mWidth / 2.0; + double centerY = mHeight / 2.0; + ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) ); + SetMovieMatrix( mMovieHandle, &transform ); + } + + // update movie controller + if ( mMovieController ) + { + MCSetControllerPort( mMovieController, mGWorldHandle ); + MCPositionController( mMovieController, &dest_rect, &dest_rect, + mcTopLeftMovie | mcPositionDontInvalidate ); + MCMovieChanged( mMovieController, mMovieHandle ); + } + + + // Emit event with size change so the calling app knows about it too + // TODO: + //LLMediaEvent event( this ); + //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); + + return true; + } + static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ) + { + Boolean result = false; + + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + switch( action ) + { + // handle window resizing + case mcActionControllerSizeChanged: + // Ensure that the movie draws correctly at the new size + self->sizeChanged(); + break; + + // Block any movie controller actions that open URLs. + case mcActionLinkToURL: + case mcActionGetNextURL: + case mcActionLinkToURLExtended: + // Prevent the movie controller from handling the message + result = true; + break; + + default: + break; + }; + + return result; + }; + + static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref ) + { + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + // IMPORTANT: typically, a consumer who is observing this event will set a flag + // when this event is fired then render later. Be aware that the media stream + // can change during this period - dimensions, depth, format etc. + //LLMediaEvent event( self ); +// self->updateQuickTime(); + // TODO ^^^ + + + if ( self->mWidth > 0 && self->mHeight > 0 ) + self->setDirty( 0, 0, self->mWidth, self->mHeight ); + + return noErr; + }; + + static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) + { + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + // TODO: + //LLMediaEvent event( self ); + //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); + + // Send a "navigate complete" event. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message.setValue("uri", self->mNavigateURL); + message.setValueS32("result_code", 200); + message.setValue("result_string", "OK"); + self->sendMessage(message); + }; + + + void rewind() + { + GoToBeginningOfMovie( mMovieHandle ); + MCMovieChanged( mMovieController, mMovieHandle ); + }; + + bool processState() + { + if ( mCommand == COMMAND_PLAY ) + { + if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING || mStatus == STATUS_DONE ) + { + long state = GetMovieLoadState( mMovieHandle ); + + if ( state >= kMovieLoadStatePlaythroughOK ) + { + // if the movie is at the end (generally because it reached it naturally) + // and we play is requested, jump back to the start of the movie. + // note: this is different from having loop flag set. + if ( IsMovieDone( mMovieHandle ) ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + rewind(); + }; + + MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + setStatus(STATUS_PLAYING); + mCommand = COMMAND_NONE; + }; + }; + } + else + if ( mCommand == COMMAND_STOP ) + { + if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED || mStatus == STATUS_DONE ) + { + if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + rewind(); + + setStatus(STATUS_LOADED); + mCommand = COMMAND_NONE; + }; + }; + } + else + if ( mCommand == COMMAND_PAUSE ) + { + if ( mStatus == STATUS_PLAYING ) + { + if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + setStatus(STATUS_PAUSED); + mCommand = COMMAND_NONE; + }; + }; + }; + + return true; + }; + + void play(F64 rate) + { + mPlayRate = rate; + mCommand = COMMAND_PLAY; + }; + + void stop() + { + mCommand = COMMAND_STOP; + }; + + void pause() + { + mCommand = COMMAND_PAUSE; + }; + + void getMovieNaturalSize(int *movie_width, int *movie_height) + { + Rect rect; + + GetMovieNaturalBoundsRect( mMovieHandle, &rect ); + + int width = ( rect.right - rect.left ); + int height = ( rect.bottom - rect.top ); + + // make sure width and height fall in valid range + if ( width < mMinWidth ) + width = mMinWidth; + + if ( width > mMaxWidth ) + width = mMaxWidth; + + if ( height < mMinHeight ) + height = mMinHeight; + + if ( height > mMaxHeight ) + height = mMaxHeight; + + // return the new rect + *movie_width = width; + *movie_height = height; + } + + void updateQuickTime(int milliseconds) + { + if ( ! mMovieHandle ) + return; + + if ( ! mMovieController ) + return; + + // service QuickTime + // Calling it this way doesn't have good behavior on Windows... +// MoviesTask( mMovieHandle, milliseconds ); + // This was the original, but I think using both MoviesTask and MCIdle is redundant. Trying with only MCIdle. +// MoviesTask( mMovieHandle, 0 ); + + MCIdle( mMovieController ); + + if ( ! mGWorldHandle ) + return; + + if ( mMediaSizeChanging ) + return; + + // update state machine + processState(); + + // see if title arrived and if so, update member variable with contents + checkTitle(); + + // QT call to see if we are at the end - can't do with controller + if ( IsMovieDone( mMovieHandle ) ) + { + // special code for looping - need to rewind at the end of the movie + if ( mIsLooping ) + { + // go back to start + rewind(); + + if ( mMovieController ) + { + // kick off new play + MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); + + // set the volume + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + }; + } + else + { + if(mStatus == STATUS_PLAYING) + { + setStatus(STATUS_DONE); + } + } + } + + }; + + int getDataWidth() const + { + if ( mGWorldHandle ) + { + int depth = mDepth; + + if (depth < 1) + depth = 1; + + // ALWAYS use the row bytes from the PixMap if we have a GWorld because + // sometimes it's not the same as mMediaDepth * mMediaWidth ! + PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); + return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth; + } + else + { + // TODO : return LLMediaImplCommon::getaDataWidth(); + return 0; + } + }; + + void seek( F64 time ) + { + if ( mMovieController ) + { + TimeRecord when; + when.scale = GetMovieTimeScale( mMovieHandle ); + when.base = 0; + + // 'time' is in (floating point) seconds. The timebase time will be in 'units', where + // there are 'scale' units per second. + SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) ); + + when.value.hi = ( SInt32 )( raw_time >> 32 ); + when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) ); + + MCDoAction( mMovieController, mcActionGoToTime, &when ); + }; + }; + + F64 getLoadedDuration() + { + TimeValue duration; + if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr) + { + // If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie. + duration = GetMovieDuration( mMovieHandle ); + } + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)duration / (F64)scale; + }; + + F64 getDuration() + { + TimeValue duration = GetMovieDuration( mMovieHandle ); + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)duration / (F64)scale; + }; + + F64 getCurrentTime() + { + TimeValue curr_time = GetMovieTime( mMovieHandle, 0 ); + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)curr_time / (F64)scale; + }; + + void setVolume( F64 volume ) + { + mCurVolume = (short)(volume * ( double ) 0x100 ); + + if ( mMovieController ) + { + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds = 0) + { + updateQuickTime(milliseconds); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( unsigned char key ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // Grab movie title into mMovieTitle - should be called repeatedly + // until it returns true since movie title takes a while to become + // available. + const bool getMovieTitle() + { + // grab meta data from movie + QTMetaDataRef media_data_ref; + OSErr result = QTCopyMovieMetaData( mMovieHandle, &media_data_ref ); + if ( noErr != result ) + return false; + + // look up "Display Name" in meta data + OSType meta_data_key = kQTMetaDataCommonKeyDisplayName; + QTMetaDataItem item = kQTMetaDataItemUninitialized; + result = QTMetaDataGetNextItem( media_data_ref, kQTMetaDataStorageFormatWildcard, + 0, kQTMetaDataKeyFormatCommon, + (const UInt8 *)&meta_data_key, + sizeof( meta_data_key ), &item ); + if ( noErr != result ) + return false; + + // find the size of the title + ByteCount size; + result = QTMetaDataGetItemValue( media_data_ref, item, NULL, 0, &size ); + if ( noErr != result || size <= 0 ) + return false; + + // allocate some space and grab it + UInt8* item_data = new UInt8( size ); + memset( item_data, 0, size * sizeof( UInt8* ) ); + result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL ); + if ( noErr != result ) + return false; + + // save it + mMovieTitle = std::string( (char* )item_data ); + + // clean up + delete [] item_data; + + return true; + }; + + // called regularly to see if title changed + void checkTitle() + { + // we did already receive title so keep checking + if ( ! mReceivedTitle ) + { + // grab title from movie meta data + if ( getMovieTitle() ) + { + // pass back to host application + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", mMovieTitle ); + sendMessage( message ); + + // stop looking once we find a title for this movie. + // TODO: this may to be reset if movie title changes + // during playback but this is okay for now + mReceivedTitle = true; + }; + }; + }; +}; + +MediaPluginQuickTime::MediaPluginQuickTime( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data), + mMinWidth( 0 ), + mMaxWidth( 2048 ), + mMinHeight( 0 ), + mMaxHeight( 2048 ) +{ +// std::cerr << "MediaPluginQuickTime constructor" << std::endl; + + mNaturalWidth = -1; + mNaturalHeight = -1; + mMovieHandle = 0; + mGWorldHandle = 0; + mMovieController = 0; + mCurVolume = 0x99; + mMediaSizeChanging = false; + mIsLooping = false; + mMovieTitle = std::string(); + mReceivedTitle = false; + mCommand = COMMAND_NONE; + mPlayRate = 0.0f; + mStatus = STATUS_NONE; +} + +MediaPluginQuickTime::~MediaPluginQuickTime() +{ +// std::cerr << "MediaPluginQuickTime destructor" << std::endl; + + ExitMovies(); + +#ifdef LL_WINDOWS + TerminateQTML(); +// std::cerr << "QuickTime closing down" << std::endl; +#endif +} + + +void MediaPluginQuickTime::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + // Normally a plugin would only specify one of these two subclasses, but this is a demo... + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + #ifdef LL_WINDOWS + + // QuickTime 7.6.4 has an issue (that was not present in 7.6.2) with initializing QuickTime + // according to this article: http://lists.apple.com/archives/QuickTime-API/2009/Sep/msg00097.html + // The solution presented there appears to work. + QTLoadLibrary("qtcf.dll"); + + // main initialization for QuickTime - only required on Windows + OSErr result = InitializeQTML( 0L ); + if ( result != noErr ) + { + //TODO: If no QT on Windows, this fails - respond accordingly. + } + else + { + //std::cerr << "QuickTime initialized" << std::endl; + }; + #endif + + // required for both Windows and Mac + EnterMovies(); + + std::string plugin_version = "QuickTime media plugin, QuickTime version "; + + long version = 0; + Gestalt( gestaltQuickTimeVersion, &version ); + std::ostringstream codec( "" ); + codec << std::hex << version << std::dec; + plugin_version += codec.str(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + #if defined(LL_WINDOWS) + // Values for Windows + mDepth = 3; + message.setValueU32("format", GL_RGB); + message.setValueU32("type", GL_UNSIGNED_BYTE); + + // We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even. + // Padding to a multiple of 3*32 guarantees it'll divide out properly. + message.setValueU32("padding", 32 * 3); + #else + // Values for Mac + mDepth = 4; + message.setValueU32("format", GL_BGRA_EXT); + #ifdef __BIG_ENDIAN__ + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV ); + #else + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8); + #endif + + // Pad texture width to a multiple of 32 bytes, to line up with cache lines. + message.setValueU32("padding", 32); + #endif + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // TODO: clean up here + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); +// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + + // Make sure the movie GWorld is no longer pointed at the shared segment. + sizeChanged(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + //std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { +// std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl; +// std::cerr << "%%%% texture size is " << texture_width << " by " << texture_height << std::endl; + + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + mMediaSizeChanging = false; + + sizeChanged(); + + update(); + }; + }; + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + load( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + F64 rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + F64 time = message_in.getValueReal("time"); + seek(time); + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + F64 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl; + }; + }; +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data); + *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + +#else // LL_QUICKTIME_ENABLED + +// Stubbed-out class with constructor/destructor (necessary or windows linker +// will just think its dead code and optimize it all out) +class MediaPluginQuickTime : public MediaPluginBase +{ +public: + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginQuickTime(); + /* virtual */ void receiveMessage(const char *message_string); +}; + +MediaPluginQuickTime::MediaPluginQuickTime( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data) +{ + // no-op +} + +MediaPluginQuickTime::~MediaPluginQuickTime() +{ + // no-op +} + +void MediaPluginQuickTime::receiveMessage(const char *message_string) +{ + // no-op +} + +// We're building without quicktime enabled. Just refuse to initialize. +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return -1; +} + +#endif // LL_QUICKTIME_ENABLED diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml index 669235af1bc0cb7620a6e2b88b3b172923a36798..ab18febcccc91213aa7902d8a0415c0504aaf585 100644 --- a/indra/newview/app_settings/ignorable_dialogs.xml +++ b/indra/newview/app_settings/ignorable_dialogs.xml @@ -1,291 +1,291 @@ -<?xml version="1.0" ?> -<llsd> -<map> - <key>FirstAppearance</key> - <map> - <key>Comment</key> - <string>Enables FirstAppearance warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstAttach</key> - <map> - <key>Comment</key> - <string>Enables FirstAttach warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstBalanceDecrease</key> - <map> - <key>Comment</key> - <string>Enables FirstBalanceDecrease warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstBalanceIncrease</key> - <map> - <key>Comment</key> - <string>Enables FirstBalanceIncrease warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstBuild</key> - <map> - <key>Comment</key> - <string>Enables FirstBuild warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstDebugMenus</key> - <map> - <key>Comment</key> - <string>Enables FirstDebugMenus warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstFlexible</key> - <map> - <key>Comment</key> - <string>Enables FirstFlexible warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstGoTo</key> - <map> - <key>Comment</key> - <string>Enables FirstGoTo warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstInventory</key> - <map> - <key>Comment</key> - <string>Enables FirstInventory warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstLeftClickNoHit</key> - <map> - <key>Comment</key> - <string>Enables FirstLeftClickNoHit warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstMap</key> - <map> - <key>Comment</key> - <string>Enables FirstMap warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstMedia</key> - <map> - <key>Comment</key> - <string>Enables FirstMedia warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstOverrideKeys</key> - <map> - <key>Comment</key> - <string>Enables FirstOverrideKeys warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstSandbox</key> - <map> - <key>Comment</key> - <string>Enables FirstSandbox warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstSculptedPrim</key> - <map> - <key>Comment</key> - <string>Enables FirstSculptedPrim warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstSit</key> - <map> - <key>Comment</key> - <string>Enables FirstSit warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstStreamingMusic</key> - <map> - <key>Comment</key> - <string>Enables FirstStreamingMusic warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstStreamingVideo</key> - <map> - <key>Comment</key> - <string>Enables FirstStreamingVideo warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstTeleport</key> - <map> - <key>Comment</key> - <string>Enables FirstTeleport warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FirstVoice</key> - <map> - <key>Comment</key> - <string>Enables FirstVoice warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>AboutDirectX9</key> - <map> - <key>Comment</key> - <string>Enables AboutDirectX9 warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>BrowserLaunch</key> - <map> - <key>Comment</key> - <string>Enables BrowserLaunch warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DeedObject</key> - <map> - <key>Comment</key> - <string>Enables DeedObject warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>NewClassified</key> - <map> - <key>Comment</key> - <string>Enables NewClassified warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>QuickTimeInstalled</key> - <map> - <key>Comment</key> - <string>Enables QuickTimeInstalled warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>ReturnToOwner</key> - <map> - <key>Comment</key> - <string>Enables ReturnToOwner warning dialog</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - </map> -</llsd> +<?xml version="1.0" ?> +<llsd> +<map> + <key>FirstAppearance</key> + <map> + <key>Comment</key> + <string>Enables FirstAppearance warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstAttach</key> + <map> + <key>Comment</key> + <string>Enables FirstAttach warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstBalanceDecrease</key> + <map> + <key>Comment</key> + <string>Enables FirstBalanceDecrease warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstBalanceIncrease</key> + <map> + <key>Comment</key> + <string>Enables FirstBalanceIncrease warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstBuild</key> + <map> + <key>Comment</key> + <string>Enables FirstBuild warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstDebugMenus</key> + <map> + <key>Comment</key> + <string>Enables FirstDebugMenus warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstFlexible</key> + <map> + <key>Comment</key> + <string>Enables FirstFlexible warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstGoTo</key> + <map> + <key>Comment</key> + <string>Enables FirstGoTo warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstInventory</key> + <map> + <key>Comment</key> + <string>Enables FirstInventory warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstLeftClickNoHit</key> + <map> + <key>Comment</key> + <string>Enables FirstLeftClickNoHit warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstMap</key> + <map> + <key>Comment</key> + <string>Enables FirstMap warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstMedia</key> + <map> + <key>Comment</key> + <string>Enables FirstMedia warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstOverrideKeys</key> + <map> + <key>Comment</key> + <string>Enables FirstOverrideKeys warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstSandbox</key> + <map> + <key>Comment</key> + <string>Enables FirstSandbox warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstSculptedPrim</key> + <map> + <key>Comment</key> + <string>Enables FirstSculptedPrim warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstSit</key> + <map> + <key>Comment</key> + <string>Enables FirstSit warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstStreamingMusic</key> + <map> + <key>Comment</key> + <string>Enables FirstStreamingMusic warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstStreamingVideo</key> + <map> + <key>Comment</key> + <string>Enables FirstStreamingVideo warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstTeleport</key> + <map> + <key>Comment</key> + <string>Enables FirstTeleport warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>FirstVoice</key> + <map> + <key>Comment</key> + <string>Enables FirstVoice warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AboutDirectX9</key> + <map> + <key>Comment</key> + <string>Enables AboutDirectX9 warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>BrowserLaunch</key> + <map> + <key>Comment</key> + <string>Enables BrowserLaunch warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>DeedObject</key> + <map> + <key>Comment</key> + <string>Enables DeedObject warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>NewClassified</key> + <map> + <key>Comment</key> + <string>Enables NewClassified warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>QuickTimeInstalled</key> + <map> + <key>Comment</key> + <string>Enables QuickTimeInstalled warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>ReturnToOwner</key> + <map> + <key>Comment</key> + <string>Enables ReturnToOwner warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + </map> +</llsd> diff --git a/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt b/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt index 185c0180fbb9c3468de11947bed9278f697d3720..30f9349111d117a99d4af183bfb11607286239b0 100644 --- a/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt +++ b/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt @@ -1,6 +1,6 @@ -The language files in this directory are Unicode (Little-Endian) format, also known as UTF-16 LE. - -This is the format required for NSIS Unicode. See http://www.scratchpaper.com/ for details. - -James Cook -September 2008 +The language files in this directory are Unicode (Little-Endian) format, also known as UTF-16 LE. + +This is the format required for NSIS Unicode. See http://www.scratchpaper.com/ for details. + +James Cook +September 2008 diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 88658f7b9f635581ffeb9973987d00ab18daec42..b01293d17c73ada9fc880c0e8f3f2c5c7cfd8796 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -1,343 +1,343 @@ -/** - * @file llfloaterabout.cpp - * @author James Cook - * @brief The about box from Help->About - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterabout.h" - -// Viewer includes -#include "llagent.h" -#include "llappviewer.h" -#include "llsecondlifeurls.h" -#include "llvoiceclient.h" -#include "lluictrlfactory.h" -#include "llviewertexteditor.h" -#include "llviewercontrol.h" -#include "llviewerstats.h" -#include "llviewerregion.h" -#include "llversionviewer.h" -#include "llviewerbuild.h" -#include "llweb.h" - -// Linden library includes -#include "llaudioengine.h" -#include "llbutton.h" -#include "llcurl.h" -#include "llglheaders.h" -#include "llfloater.h" -#include "llfloaterreg.h" -#include "llimagej2c.h" -#include "llsys.h" -#include "lltrans.h" -#include "lluri.h" -#include "v3dmath.h" -#include "llwindow.h" -#include "stringize.h" -#include "llsdutil_math.h" -#include "lleventdispatcher.h" - -#if LL_WINDOWS -#include "lldxhardware.h" -#endif - -extern LLMemoryInfo gSysMemory; -extern U32 gPacketsIn; - -static std::string get_viewer_release_notes_url(); - - -///---------------------------------------------------------------------------- -/// Class LLFloaterAbout -///---------------------------------------------------------------------------- -class LLFloaterAbout - : public LLFloater -{ - friend class LLFloaterReg; -private: - LLFloaterAbout(const LLSD& key); - virtual ~LLFloaterAbout(); - -public: - /*virtual*/ BOOL postBuild(); - - /// Obtain the data used to fill out the contents string. This is - /// separated so that we can programmatically access the same info. - static LLSD getInfo(); - void onClickCopyToClipboard(); -}; - - -// Default constructor -LLFloaterAbout::LLFloaterAbout(const LLSD& key) -: LLFloater(key) -{ - //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml"); - -} - -// Destroys the object -LLFloaterAbout::~LLFloaterAbout() -{ -} - -BOOL LLFloaterAbout::postBuild() -{ - center(); - LLViewerTextEditor *support_widget = - getChild<LLViewerTextEditor>("support_editor", true); - - LLViewerTextEditor *credits_widget = - getChild<LLViewerTextEditor>("credits_editor", true); - - getChild<LLUICtrl>("copy_btn")->setCommitCallback( - boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this)); - -#if LL_WINDOWS - getWindow()->incBusyCount(); - getWindow()->setCursor(UI_CURSOR_ARROW); -#endif - LLSD info(getInfo()); -#if LL_WINDOWS - getWindow()->decBusyCount(); - getWindow()->setCursor(UI_CURSOR_ARROW); -#endif - - std::ostringstream support; - - // Render the LLSD from getInfo() as a format_map_t - LLStringUtil::format_map_t args; - // For reasons I don't yet understand, [ReleaseNotes] is not part of the - // default substitution strings whereas [APP_NAME] is. But it works to - // simply copy it into these specific args. - args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes"); - 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] = getString("none"); - } - 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 << getString("AboutHeader", args); - if (info.has("COMPILER")) - { - support << "\n\n" << getString("AboutCompiler", args); - } - if (info.has("REGION")) - { - support << "\n\n" << getString("AboutPosition", args); - } - support << "\n\n" << getString("AboutSystem", args); - if (info.has("GRAPHICS_DRIVER_VERSION")) - { - support << "\n\n" << getString("AboutDriver", args); - } - support << "\n\n" << getString("AboutLibs", args); - if (info.has("PACKETS_IN")) - { - support << '\n' << getString("AboutTraffic", args); - } - - support_widget->appendText(support.str(), - FALSE, - LLStyle::Params() - .color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor"))); - support_widget->blockUndo(); - - // Fix views - support_widget->setCursorPos(0); - support_widget->setEnabled(FALSE); - - credits_widget->setCursorPos(0); - credits_widget->setEnabled(FALSE); - - return TRUE; -} - -// static -LLSD LLFloaterAbout::getInfo() -{ - // 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; - LLSD version; - version.append(LL_VERSION_MAJOR); - version.append(LL_VERSION_MINOR); - version.append(LL_VERSION_PATCH); - version.append(LL_VERSION_BUILD); - info["VIEWER_VERSION"] = version; - info["VIEWER_VERSION_STR"] = STRINGIZE(version[0].asInteger() << '.' << - version[1].asInteger() << '.' << - version[2].asInteger() << '.' << - version[3].asInteger()); - info["BUILD_DATE"] = __DATE__; - info["BUILD_TIME"] = __TIME__; - info["CHANNEL"] = gSavedSettings.getString("VersionChannelName"); - - info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url(); - -#if LL_MSVC - info["COMPILER"] = "MSVC"; - info["COMPILER_VERSION"] = _MSC_VER; -#elif LL_GNUC - info["COMPILER"] = "GCC"; - info["COMPILER_VERSION"] = GCC_VERSION; -#endif - - // Position - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - const LLVector3d &pos = gAgent.getPositionGlobal(); - info["POSITION"] = ll_sd_from_vector3d(pos); - info["REGION"] = gAgent.getRegion()->getName(); - info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); - info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); - info["SERVER_VERSION"] = gLastVersionChannel; - info["SERVER_RELEASE_NOTES_URL"] = LLWeb::escapeURL(region->getCapability("ServerReleaseNotes")); - } - - // CPU - info["CPU"] = gSysCPU.getCPUString(); - info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB() / 1024); - // Moved hack adjustment to Windows memory size into llsys.cpp - info["OS_VERSION"] = LLAppViewer::instance()->getOSInfo().getOSString(); - info["GRAPHICS_CARD_VENDOR"] = (const char*)(glGetString(GL_VENDOR)); - info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER)); - -#if LL_WINDOWS - LLSD driver_info = gDXHardware.getDisplayInfo(); - if (driver_info.has("DriverVersion")) - { - info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; - } -#endif - - info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); - info["LIBCURL_VERSION"] = LLCurl::getVersionString(); - info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); - bool want_fullname = true; - info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD(); - info["VIVOX_VERSION"] = gVoiceClient ? gVoiceClient->getAPIVersion() : "Unknown"; - - // TODO: Implement media plugin version query - info["QT_WEBKIT_VERSION"] = "4.5.2"; - - if (gPacketsIn > 0) - { - info["PACKETS_LOST"] = LLViewerStats::getInstance()->mPacketsLostStat.getCurrent(); - info["PACKETS_IN"] = F32(gPacketsIn); - info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); - } - - return info; -} - -static std::string get_viewer_release_notes_url() -{ - std::ostringstream version; - version << LL_VERSION_MAJOR << "." - << LL_VERSION_MINOR << "." - << LL_VERSION_PATCH << "." - << LL_VERSION_BUILD; - - LLSD query; - query["channel"] = gSavedSettings.getString("VersionChannelName"); - query["version"] = version.str(); - - std::ostringstream url; - url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query); - - return LLWeb::escapeURL(url.str()); -} - -class LLFloaterAboutListener: public LLDispatchListener -{ -public: - LLFloaterAboutListener(): - LLDispatchListener("LLFloaterAbout", "op") - { - add("getInfo", &LLFloaterAboutListener::getInfo, LLSD().insert("reply", LLSD())); - } - -private: - void getInfo(const LLSD& request) const - { - LLReqID reqid(request); - LLSD reply(LLFloaterAbout::getInfo()); - reqid.stamp(reply); - LLEventPumps::instance().obtain(request["reply"]).post(reply); - } -}; - -static LLFloaterAboutListener floaterAboutListener; - -void LLFloaterAbout::onClickCopyToClipboard() -{ - LLViewerTextEditor *support_widget = - getChild<LLViewerTextEditor>("support_editor", true); - support_widget->selectAll(); - support_widget->copy(); - support_widget->deselect(); -} - -///---------------------------------------------------------------------------- -/// LLFloaterAboutUtil -///---------------------------------------------------------------------------- -void LLFloaterAboutUtil::registerFloater() -{ - LLFloaterReg::add("sl_about", "floater_about.xml", - &LLFloaterReg::build<LLFloaterAbout>); - -} +/** + * @file llfloaterabout.cpp + * @author James Cook + * @brief The about box from Help->About + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterabout.h" + +// Viewer includes +#include "llagent.h" +#include "llappviewer.h" +#include "llsecondlifeurls.h" +#include "llvoiceclient.h" +#include "lluictrlfactory.h" +#include "llviewertexteditor.h" +#include "llviewercontrol.h" +#include "llviewerstats.h" +#include "llviewerregion.h" +#include "llversionviewer.h" +#include "llviewerbuild.h" +#include "llweb.h" + +// Linden library includes +#include "llaudioengine.h" +#include "llbutton.h" +#include "llcurl.h" +#include "llglheaders.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "llimagej2c.h" +#include "llsys.h" +#include "lltrans.h" +#include "lluri.h" +#include "v3dmath.h" +#include "llwindow.h" +#include "stringize.h" +#include "llsdutil_math.h" +#include "lleventdispatcher.h" + +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + +extern LLMemoryInfo gSysMemory; +extern U32 gPacketsIn; + +static std::string get_viewer_release_notes_url(); + + +///---------------------------------------------------------------------------- +/// Class LLFloaterAbout +///---------------------------------------------------------------------------- +class LLFloaterAbout + : public LLFloater +{ + friend class LLFloaterReg; +private: + LLFloaterAbout(const LLSD& key); + virtual ~LLFloaterAbout(); + +public: + /*virtual*/ BOOL postBuild(); + + /// Obtain the data used to fill out the contents string. This is + /// separated so that we can programmatically access the same info. + static LLSD getInfo(); + void onClickCopyToClipboard(); +}; + + +// Default constructor +LLFloaterAbout::LLFloaterAbout(const LLSD& key) +: LLFloater(key) +{ + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml"); + +} + +// Destroys the object +LLFloaterAbout::~LLFloaterAbout() +{ +} + +BOOL LLFloaterAbout::postBuild() +{ + center(); + LLViewerTextEditor *support_widget = + getChild<LLViewerTextEditor>("support_editor", true); + + LLViewerTextEditor *credits_widget = + getChild<LLViewerTextEditor>("credits_editor", true); + + getChild<LLUICtrl>("copy_btn")->setCommitCallback( + boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this)); + +#if LL_WINDOWS + getWindow()->incBusyCount(); + getWindow()->setCursor(UI_CURSOR_ARROW); +#endif + LLSD info(getInfo()); +#if LL_WINDOWS + getWindow()->decBusyCount(); + getWindow()->setCursor(UI_CURSOR_ARROW); +#endif + + std::ostringstream support; + + // Render the LLSD from getInfo() as a format_map_t + LLStringUtil::format_map_t args; + // For reasons I don't yet understand, [ReleaseNotes] is not part of the + // default substitution strings whereas [APP_NAME] is. But it works to + // simply copy it into these specific args. + args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes"); + 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] = getString("none"); + } + 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 << getString("AboutHeader", args); + if (info.has("COMPILER")) + { + support << "\n\n" << getString("AboutCompiler", args); + } + if (info.has("REGION")) + { + support << "\n\n" << getString("AboutPosition", args); + } + support << "\n\n" << getString("AboutSystem", args); + if (info.has("GRAPHICS_DRIVER_VERSION")) + { + support << "\n\n" << getString("AboutDriver", args); + } + support << "\n\n" << getString("AboutLibs", args); + if (info.has("PACKETS_IN")) + { + support << '\n' << getString("AboutTraffic", args); + } + + support_widget->appendText(support.str(), + FALSE, + LLStyle::Params() + .color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor"))); + support_widget->blockUndo(); + + // Fix views + support_widget->setCursorPos(0); + support_widget->setEnabled(FALSE); + + credits_widget->setCursorPos(0); + credits_widget->setEnabled(FALSE); + + return TRUE; +} + +// static +LLSD LLFloaterAbout::getInfo() +{ + // 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; + LLSD version; + version.append(LL_VERSION_MAJOR); + version.append(LL_VERSION_MINOR); + version.append(LL_VERSION_PATCH); + version.append(LL_VERSION_BUILD); + info["VIEWER_VERSION"] = version; + info["VIEWER_VERSION_STR"] = STRINGIZE(version[0].asInteger() << '.' << + version[1].asInteger() << '.' << + version[2].asInteger() << '.' << + version[3].asInteger()); + info["BUILD_DATE"] = __DATE__; + info["BUILD_TIME"] = __TIME__; + info["CHANNEL"] = gSavedSettings.getString("VersionChannelName"); + + info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url(); + +#if LL_MSVC + info["COMPILER"] = "MSVC"; + info["COMPILER_VERSION"] = _MSC_VER; +#elif LL_GNUC + info["COMPILER"] = "GCC"; + info["COMPILER_VERSION"] = GCC_VERSION; +#endif + + // Position + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + const LLVector3d &pos = gAgent.getPositionGlobal(); + info["POSITION"] = ll_sd_from_vector3d(pos); + info["REGION"] = gAgent.getRegion()->getName(); + info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); + info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); + info["SERVER_VERSION"] = gLastVersionChannel; + info["SERVER_RELEASE_NOTES_URL"] = LLWeb::escapeURL(region->getCapability("ServerReleaseNotes")); + } + + // CPU + info["CPU"] = gSysCPU.getCPUString(); + info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB() / 1024); + // Moved hack adjustment to Windows memory size into llsys.cpp + info["OS_VERSION"] = LLAppViewer::instance()->getOSInfo().getOSString(); + info["GRAPHICS_CARD_VENDOR"] = (const char*)(glGetString(GL_VENDOR)); + info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER)); + +#if LL_WINDOWS + LLSD driver_info = gDXHardware.getDisplayInfo(); + if (driver_info.has("DriverVersion")) + { + info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; + } +#endif + + info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); + info["LIBCURL_VERSION"] = LLCurl::getVersionString(); + info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); + bool want_fullname = true; + info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD(); + info["VIVOX_VERSION"] = gVoiceClient ? gVoiceClient->getAPIVersion() : "Unknown"; + + // TODO: Implement media plugin version query + info["QT_WEBKIT_VERSION"] = "4.5.2"; + + if (gPacketsIn > 0) + { + info["PACKETS_LOST"] = LLViewerStats::getInstance()->mPacketsLostStat.getCurrent(); + info["PACKETS_IN"] = F32(gPacketsIn); + info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal(); + } + + return info; +} + +static std::string get_viewer_release_notes_url() +{ + std::ostringstream version; + version << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; + + LLSD query; + query["channel"] = gSavedSettings.getString("VersionChannelName"); + query["version"] = version.str(); + + std::ostringstream url; + url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query); + + return LLWeb::escapeURL(url.str()); +} + +class LLFloaterAboutListener: public LLDispatchListener +{ +public: + LLFloaterAboutListener(): + LLDispatchListener("LLFloaterAbout", "op") + { + add("getInfo", &LLFloaterAboutListener::getInfo, LLSD().insert("reply", LLSD())); + } + +private: + void getInfo(const LLSD& request) const + { + LLReqID reqid(request); + LLSD reply(LLFloaterAbout::getInfo()); + reqid.stamp(reply); + LLEventPumps::instance().obtain(request["reply"]).post(reply); + } +}; + +static LLFloaterAboutListener floaterAboutListener; + +void LLFloaterAbout::onClickCopyToClipboard() +{ + LLViewerTextEditor *support_widget = + getChild<LLViewerTextEditor>("support_editor", true); + support_widget->selectAll(); + support_widget->copy(); + support_widget->deselect(); +} + +///---------------------------------------------------------------------------- +/// LLFloaterAboutUtil +///---------------------------------------------------------------------------- +void LLFloaterAboutUtil::registerFloater() +{ + LLFloaterReg::add("sl_about", "floater_about.xml", + &LLFloaterReg::build<LLFloaterAbout>); + +} diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index 89a9a317c2715b261afe4d8b3472f399a46817dd..8570b5eb4a7bf910ff82d527125c8a406bd0f4f2 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1,155 +1,155 @@ -/** - * @file llfloaterinventory.cpp - * @brief Implementation of the inventory view and associated stuff. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterinventory.h" - -#include "llagent.h" -#include "llfirstuse.h" -#include "llfloaterreg.h" -#include "llinventorymodel.h" -#include "llpanelmaininventory.h" -#include "llresmgr.h" - -///---------------------------------------------------------------------------- -/// LLFloaterInventory -///---------------------------------------------------------------------------- - -LLFloaterInventory::LLFloaterInventory(const LLSD& key) - : LLFloater(key) -{ -} - -LLFloaterInventory::~LLFloaterInventory() -{ -} - -BOOL LLFloaterInventory::postBuild() -{ - mPanelMainInventory = getChild<LLPanelMainInventory>("Inventory Panel"); - return TRUE; -} - - -void LLFloaterInventory::draw() -{ - if (LLInventoryModel::isEverythingFetched()) - { - updateTitle(); - } - LLFloater::draw(); -} - -void LLFloaterInventory::updateTitle() -{ - LLLocale locale(LLLocale::USER_LOCALE); - std::string item_count_string; - LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount()); - - LLStringUtil::format_map_t string_args; - string_args["[ITEM_COUNT]"] = item_count_string; - string_args["[FILTER]"] = mPanelMainInventory->getFilterText(); - - if (LLInventoryModel::backgroundFetchActive()) - { - setTitle(getString("TitleFetching", string_args)); - } - else - { - setTitle(getString("TitleCompleted", string_args)); - } -} - -void LLFloaterInventory::changed(U32 mask) -{ - updateTitle(); -} - -LLInventoryPanel* LLFloaterInventory::getPanel() -{ - if (mPanelMainInventory) - return mPanelMainInventory->getPanel(); - return NULL; -} - -// static -LLFloaterInventory* LLFloaterInventory::showAgentInventory() -{ - LLFloaterInventory* iv = NULL; - if (!gAgent.cameraMouselook()) - { - iv = LLFloaterReg::showTypedInstance<LLFloaterInventory>("inventory", LLSD()); - } - return iv; -} - -// static -LLFloaterInventory* LLFloaterInventory::getActiveInventory() -{ - LLFloaterInventory* res = NULL; - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); - S32 z_min = S32_MAX; - for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) - { - LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*iter); - if (iv) - { - S32 z_order = gFloaterView->getZOrder(iv); - if (z_order < z_min) - { - res = iv; - z_min = z_order; - } - } - } - return res; -} - -// static -void LLFloaterInventory::cleanup() -{ - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); - for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();) - { - LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*iter++); - if (iv) - { - iv->destroy(); - } - } -} - -void LLFloaterInventory::onOpen(const LLSD& key) -{ - LLFirstUse::useInventory(); -} +/** + * @file llfloaterinventory.cpp + * @brief Implementation of the inventory view and associated stuff. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterinventory.h" + +#include "llagent.h" +#include "llfirstuse.h" +#include "llfloaterreg.h" +#include "llinventorymodel.h" +#include "llpanelmaininventory.h" +#include "llresmgr.h" + +///---------------------------------------------------------------------------- +/// LLFloaterInventory +///---------------------------------------------------------------------------- + +LLFloaterInventory::LLFloaterInventory(const LLSD& key) + : LLFloater(key) +{ +} + +LLFloaterInventory::~LLFloaterInventory() +{ +} + +BOOL LLFloaterInventory::postBuild() +{ + mPanelMainInventory = getChild<LLPanelMainInventory>("Inventory Panel"); + return TRUE; +} + + +void LLFloaterInventory::draw() +{ + if (LLInventoryModel::isEverythingFetched()) + { + updateTitle(); + } + LLFloater::draw(); +} + +void LLFloaterInventory::updateTitle() +{ + LLLocale locale(LLLocale::USER_LOCALE); + std::string item_count_string; + LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount()); + + LLStringUtil::format_map_t string_args; + string_args["[ITEM_COUNT]"] = item_count_string; + string_args["[FILTER]"] = mPanelMainInventory->getFilterText(); + + if (LLInventoryModel::backgroundFetchActive()) + { + setTitle(getString("TitleFetching", string_args)); + } + else + { + setTitle(getString("TitleCompleted", string_args)); + } +} + +void LLFloaterInventory::changed(U32 mask) +{ + updateTitle(); +} + +LLInventoryPanel* LLFloaterInventory::getPanel() +{ + if (mPanelMainInventory) + return mPanelMainInventory->getPanel(); + return NULL; +} + +// static +LLFloaterInventory* LLFloaterInventory::showAgentInventory() +{ + LLFloaterInventory* iv = NULL; + if (!gAgent.cameraMouselook()) + { + iv = LLFloaterReg::showTypedInstance<LLFloaterInventory>("inventory", LLSD()); + } + return iv; +} + +// static +LLFloaterInventory* LLFloaterInventory::getActiveInventory() +{ + LLFloaterInventory* res = NULL; + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + S32 z_min = S32_MAX; + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*iter); + if (iv) + { + S32 z_order = gFloaterView->getZOrder(iv); + if (z_order < z_min) + { + res = iv; + z_min = z_order; + } + } + } + return res; +} + +// static +void LLFloaterInventory::cleanup() +{ + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();) + { + LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*iter++); + if (iv) + { + iv->destroy(); + } + } +} + +void LLFloaterInventory::onOpen(const LLSD& key) +{ + LLFirstUse::useInventory(); +} diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 336025e55ee5737972e9f6eb99d164ef853ac9e6..b9775cf0e9cb954c66f98285b59e5b8336b96133 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -604,6 +604,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { disabled_items.push_back(std::string("Delete")); } + + // If multiple items are selected, disable properties (if it exists). + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Properties")); + } } void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 694f702654467aa2dce9046f6f6d00323cd9c281..77121bd922cb8dbe9fc884d6ae6d3cdb86d8cfb9 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1,344 +1,344 @@ -/** - * @file llfloaterinventory.cpp - * @brief Implementation of the inventory view and associated stuff. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include <utility> // for std::pair<> - -#include "llinventoryfunctions.h" - -// library includes -#include "llagent.h" -#include "llagentwearables.h" -#include "llcallingcard.h" -#include "llfloaterreg.h" -#include "llsdserialize.h" -#include "llfiltereditor.h" -#include "llspinctrl.h" -#include "llui.h" -#include "message.h" - -// newview includes -#include "llappearancemgr.h" -#include "llappviewer.h" -#include "llfirstuse.h" -#include "llfloaterchat.h" -#include "llfloatercustomize.h" -#include "llfocusmgr.h" -#include "llfolderview.h" -#include "llgesturemgr.h" -#include "lliconctrl.h" -#include "llimview.h" -#include "llinventorybridge.h" -#include "llinventoryclipboard.h" -#include "llinventorymodel.h" -#include "llinventorypanel.h" -#include "lllineeditor.h" -#include "llmenugl.h" -#include "llpreviewanim.h" -#include "llpreviewgesture.h" -#include "llpreviewnotecard.h" -#include "llpreviewscript.h" -#include "llpreviewsound.h" -#include "llpreviewtexture.h" -#include "llresmgr.h" -#include "llscrollbar.h" -#include "llscrollcontainer.h" -#include "llselectmgr.h" -#include "lltabcontainer.h" -#include "lltooldraganddrop.h" -#include "lluictrlfactory.h" -#include "llviewerinventory.h" -#include "llviewermessage.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llwearablelist.h" - -BOOL LLInventoryState::sWearNewClothing = FALSE; -LLUUID LLInventoryState::sWearNewClothingTransactionID; - -void LLSaveFolderState::setApply(BOOL apply) -{ - mApply = apply; - // before generating new list of open folders, clear the old one - if(!apply) - { - clearOpenFolders(); - } -} - -void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_DO_FOLDER); - if(mApply) - { - // we're applying the open state - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; - LLUUID id(bridge->getUUID()); - if(mOpenFolders.find(id) != mOpenFolders.end()) - { - folder->setOpen(TRUE); - } - else - { - // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected()) - { - folder->setOpen(FALSE); - } - } - } - else - { - // we're recording state at this point - if(folder->isOpen()) - { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; - mOpenFolders.insert(bridge->getUUID()); - } - } -} - -void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) -{ - if (item->getFiltered()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } -} - -void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) -{ - if (folder->getFiltered() && 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->getFiltered() && !folder->hasFilteredDescendants()) - { - folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); - } -} - -void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) -{ - if (item->getFiltered() && !mItemSelected) - { - item->getRoot()->setSelection(item, FALSE, FALSE); - if (item->getParentFolder()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - item->getRoot()->scrollToShowSelection(); - mItemSelected = TRUE; - } -} - -void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) -{ - if (folder->getFiltered() && !mItemSelected) - { - folder->getRoot()->setSelection(folder, FALSE, FALSE); - if (folder->getParentFolder()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - folder->getRoot()->scrollToShowSelection(); - mItemSelected = TRUE; - } -} - -void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) -{ - 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); - } -} - -const std::string& get_item_icon_name(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 attachment_point, - BOOL item_is_multi ) -{ - EInventoryIcon idx = OBJECT_ICON_NAME; - if ( item_is_multi ) - { - idx = OBJECT_MULTI_ICON_NAME; - } - - switch(asset_type) - { - case LLAssetType::AT_TEXTURE: - if(LLInventoryType::IT_SNAPSHOT == inventory_type) - { - idx = SNAPSHOT_ICON_NAME; - } - else - { - idx = TEXTURE_ICON_NAME; - } - break; - - case LLAssetType::AT_SOUND: - idx = SOUND_ICON_NAME; - break; - case LLAssetType::AT_CALLINGCARD: - if(attachment_point!= 0) - { - idx = CALLINGCARD_ONLINE_ICON_NAME; - } - else - { - idx = CALLINGCARD_OFFLINE_ICON_NAME; - } - break; - case LLAssetType::AT_LANDMARK: - if(attachment_point!= 0) - { - idx = LANDMARK_VISITED_ICON_NAME; - } - else - { - idx = LANDMARK_ICON_NAME; - } - break; - case LLAssetType::AT_SCRIPT: - case LLAssetType::AT_LSL_TEXT: - case LLAssetType::AT_LSL_BYTECODE: - idx = SCRIPT_ICON_NAME; - break; - case LLAssetType::AT_CLOTHING: - idx = CLOTHING_ICON_NAME; - case LLAssetType::AT_BODYPART : - if(LLAssetType::AT_BODYPART == asset_type) - { - idx = BODYPART_ICON_NAME; - } - switch(LLInventoryItem::II_FLAGS_WEARABLES_MASK & attachment_point) - { - case WT_SHAPE: - idx = BODYPART_SHAPE_ICON_NAME; - break; - case WT_SKIN: - idx = BODYPART_SKIN_ICON_NAME; - break; - case WT_HAIR: - idx = BODYPART_HAIR_ICON_NAME; - break; - case WT_EYES: - idx = BODYPART_EYES_ICON_NAME; - break; - case WT_SHIRT: - idx = CLOTHING_SHIRT_ICON_NAME; - break; - case WT_PANTS: - idx = CLOTHING_PANTS_ICON_NAME; - break; - case WT_SHOES: - idx = CLOTHING_SHOES_ICON_NAME; - break; - case WT_SOCKS: - idx = CLOTHING_SOCKS_ICON_NAME; - break; - case WT_JACKET: - idx = CLOTHING_JACKET_ICON_NAME; - break; - case WT_GLOVES: - idx = CLOTHING_GLOVES_ICON_NAME; - break; - case WT_UNDERSHIRT: - idx = CLOTHING_UNDERSHIRT_ICON_NAME; - break; - case WT_UNDERPANTS: - idx = CLOTHING_UNDERPANTS_ICON_NAME; - break; - case WT_SKIRT: - idx = CLOTHING_SKIRT_ICON_NAME; - break; - case WT_ALPHA: - idx = CLOTHING_ALPHA_ICON_NAME; - break; - case WT_TATTOO: - idx = CLOTHING_TATTOO_ICON_NAME; - break; - default: - // no-op, go with choice above - break; - } - break; - case LLAssetType::AT_NOTECARD: - idx = NOTECARD_ICON_NAME; - break; - case LLAssetType::AT_ANIMATION: - idx = ANIMATION_ICON_NAME; - break; - case LLAssetType::AT_GESTURE: - idx = GESTURE_ICON_NAME; - break; - case LLAssetType::AT_FAVORITE: - //TODO - need bette idx - idx = LANDMARK_ICON_NAME; - break; - case LLAssetType::AT_LINK: - idx = LINKITEM_ICON_NAME; - break; - case LLAssetType::AT_LINK_FOLDER: - idx = LINKFOLDER_ICON_NAME; - break; - default: - break; - } - - return ICON_NAME[idx]; -} - -LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 attachment_point, - BOOL item_is_multi) -{ - const std::string& icon_name = get_item_icon_name(asset_type, inventory_type, attachment_point, item_is_multi ); - return LLUI::getUIImage(icon_name); -} +/** + * @file llfloaterinventory.cpp + * @brief Implementation of the inventory view and associated stuff. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include <utility> // for std::pair<> + +#include "llinventoryfunctions.h" + +// library includes +#include "llagent.h" +#include "llagentwearables.h" +#include "llcallingcard.h" +#include "llfloaterreg.h" +#include "llsdserialize.h" +#include "llfiltereditor.h" +#include "llspinctrl.h" +#include "llui.h" +#include "message.h" + +// newview includes +#include "llappearancemgr.h" +#include "llappviewer.h" +#include "llfirstuse.h" +#include "llfloaterchat.h" +#include "llfloatercustomize.h" +#include "llfocusmgr.h" +#include "llfolderview.h" +#include "llgesturemgr.h" +#include "lliconctrl.h" +#include "llimview.h" +#include "llinventorybridge.h" +#include "llinventoryclipboard.h" +#include "llinventorymodel.h" +#include "llinventorypanel.h" +#include "lllineeditor.h" +#include "llmenugl.h" +#include "llpreviewanim.h" +#include "llpreviewgesture.h" +#include "llpreviewnotecard.h" +#include "llpreviewscript.h" +#include "llpreviewsound.h" +#include "llpreviewtexture.h" +#include "llresmgr.h" +#include "llscrollbar.h" +#include "llscrollcontainer.h" +#include "llselectmgr.h" +#include "lltabcontainer.h" +#include "lltooldraganddrop.h" +#include "lluictrlfactory.h" +#include "llviewerinventory.h" +#include "llviewermessage.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwearablelist.h" + +BOOL LLInventoryState::sWearNewClothing = FALSE; +LLUUID LLInventoryState::sWearNewClothingTransactionID; + +void LLSaveFolderState::setApply(BOOL apply) +{ + mApply = apply; + // before generating new list of open folders, clear the old one + if(!apply) + { + clearOpenFolders(); + } +} + +void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_DO_FOLDER); + if(mApply) + { + // we're applying the open state + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + LLUUID id(bridge->getUUID()); + if(mOpenFolders.find(id) != mOpenFolders.end()) + { + folder->setOpen(TRUE); + } + else + { + // keep selected filter in its current state, this is less jarring to user + if (!folder->isSelected()) + { + folder->setOpen(FALSE); + } + } + } + else + { + // we're recording state at this point + if(folder->isOpen()) + { + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + mOpenFolders.insert(bridge->getUUID()); + } + } +} + +void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) +{ + if (item->getFiltered()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} + +void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getFiltered() && 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->getFiltered() && !folder->hasFilteredDescendants()) + { + folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); + } +} + +void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) +{ + if (item->getFiltered() && !mItemSelected) + { + item->getRoot()->setSelection(item, FALSE, FALSE); + if (item->getParentFolder()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + item->getRoot()->scrollToShowSelection(); + mItemSelected = TRUE; + } +} + +void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getFiltered() && !mItemSelected) + { + folder->getRoot()->setSelection(folder, FALSE, FALSE); + if (folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + folder->getRoot()->scrollToShowSelection(); + mItemSelected = TRUE; + } +} + +void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) +{ + 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); + } +} + +const std::string& get_item_icon_name(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ) +{ + EInventoryIcon idx = OBJECT_ICON_NAME; + if ( item_is_multi ) + { + idx = OBJECT_MULTI_ICON_NAME; + } + + switch(asset_type) + { + case LLAssetType::AT_TEXTURE: + if(LLInventoryType::IT_SNAPSHOT == inventory_type) + { + idx = SNAPSHOT_ICON_NAME; + } + else + { + idx = TEXTURE_ICON_NAME; + } + break; + + case LLAssetType::AT_SOUND: + idx = SOUND_ICON_NAME; + break; + case LLAssetType::AT_CALLINGCARD: + if(attachment_point!= 0) + { + idx = CALLINGCARD_ONLINE_ICON_NAME; + } + else + { + idx = CALLINGCARD_OFFLINE_ICON_NAME; + } + break; + case LLAssetType::AT_LANDMARK: + if(attachment_point!= 0) + { + idx = LANDMARK_VISITED_ICON_NAME; + } + else + { + idx = LANDMARK_ICON_NAME; + } + break; + case LLAssetType::AT_SCRIPT: + case LLAssetType::AT_LSL_TEXT: + case LLAssetType::AT_LSL_BYTECODE: + idx = SCRIPT_ICON_NAME; + break; + case LLAssetType::AT_CLOTHING: + idx = CLOTHING_ICON_NAME; + case LLAssetType::AT_BODYPART : + if(LLAssetType::AT_BODYPART == asset_type) + { + idx = BODYPART_ICON_NAME; + } + switch(LLInventoryItem::II_FLAGS_WEARABLES_MASK & attachment_point) + { + case WT_SHAPE: + idx = BODYPART_SHAPE_ICON_NAME; + break; + case WT_SKIN: + idx = BODYPART_SKIN_ICON_NAME; + break; + case WT_HAIR: + idx = BODYPART_HAIR_ICON_NAME; + break; + case WT_EYES: + idx = BODYPART_EYES_ICON_NAME; + break; + case WT_SHIRT: + idx = CLOTHING_SHIRT_ICON_NAME; + break; + case WT_PANTS: + idx = CLOTHING_PANTS_ICON_NAME; + break; + case WT_SHOES: + idx = CLOTHING_SHOES_ICON_NAME; + break; + case WT_SOCKS: + idx = CLOTHING_SOCKS_ICON_NAME; + break; + case WT_JACKET: + idx = CLOTHING_JACKET_ICON_NAME; + break; + case WT_GLOVES: + idx = CLOTHING_GLOVES_ICON_NAME; + break; + case WT_UNDERSHIRT: + idx = CLOTHING_UNDERSHIRT_ICON_NAME; + break; + case WT_UNDERPANTS: + idx = CLOTHING_UNDERPANTS_ICON_NAME; + break; + case WT_SKIRT: + idx = CLOTHING_SKIRT_ICON_NAME; + break; + case WT_ALPHA: + idx = CLOTHING_ALPHA_ICON_NAME; + break; + case WT_TATTOO: + idx = CLOTHING_TATTOO_ICON_NAME; + break; + default: + // no-op, go with choice above + break; + } + break; + case LLAssetType::AT_NOTECARD: + idx = NOTECARD_ICON_NAME; + break; + case LLAssetType::AT_ANIMATION: + idx = ANIMATION_ICON_NAME; + break; + case LLAssetType::AT_GESTURE: + idx = GESTURE_ICON_NAME; + break; + case LLAssetType::AT_FAVORITE: + //TODO - need bette idx + idx = LANDMARK_ICON_NAME; + break; + case LLAssetType::AT_LINK: + idx = LINKITEM_ICON_NAME; + break; + case LLAssetType::AT_LINK_FOLDER: + idx = LINKFOLDER_ICON_NAME; + break; + default: + break; + } + + return ICON_NAME[idx]; +} + +LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi) +{ + const std::string& icon_name = get_item_icon_name(asset_type, inventory_type, attachment_point, item_is_multi ); + return LLUI::getUIImage(icon_name); +} diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index efd40576a76e4e1d16ad25e09239d83499bf052e..95cc68ddbe1712a1220459391ba3a61adb9d4972 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -1,136 +1,136 @@ -/** - * @file llinventoryfunctions.h - * @brief Miscellaneous inventory-related functions and classes - * class definition - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLINVENTORYFUNCTIONS_H -#define LL_LLINVENTORYFUNCTIONS_H - -#include "llassetstorage.h" -#include "lldarray.h" -#include "llfloater.h" -#include "llinventory.h" -#include "llinventoryfilter.h" -#include "llfolderview.h" -#include "llinventorymodel.h" -#include "lluictrlfactory.h" -#include <set> - - -class LLFolderViewItem; -class LLInventoryFilter; -class LLInventoryModel; -class LLInventoryPanel; -class LLInvFVBridge; -class LLInventoryFVBridgeBuilder; -class LLMenuBarGL; -class LLCheckBoxCtrl; -class LLSpinCtrl; -class LLScrollContainer; -class LLTextBox; -class LLIconCtrl; -class LLSaveFolderState; -class LLFilterEditor; -class LLTabContainer; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// This is a collection of miscellaneous functions and classes -// that don't fit cleanly into any other class header. -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -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 -}; - -class LLSelectFirstFilteredItem : public LLFolderViewFunctor -{ -public: - LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} - virtual ~LLSelectFirstFilteredItem() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); - BOOL wasItemSelected() { return mItemSelected; } -protected: - BOOL mItemSelected; -}; - -class LLOpenFilteredFolders : public LLFolderViewFunctor -{ -public: - LLOpenFilteredFolders() {} - virtual ~LLOpenFilteredFolders() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); -}; - -class LLSaveFolderState : public LLFolderViewFunctor -{ -public: - LLSaveFolderState() : mApply(FALSE) {} - virtual ~LLSaveFolderState() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item) {} - void setApply(BOOL apply); - void clearOpenFolders() { mOpenFolders.clear(); } -protected: - std::set<LLUUID> mOpenFolders; - BOOL mApply; -}; - -class LLOpenFoldersWithSelection : public LLFolderViewFunctor -{ -public: - LLOpenFoldersWithSelection() {} - virtual ~LLOpenFoldersWithSelection() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); -}; - -const std::string& get_item_icon_name(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 attachment_point, - BOOL item_is_multi ); - -LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 attachment_point, - BOOL item_is_multi ); - -#endif // LL_LLINVENTORYFUNCTIONS_H - - - +/** + * @file llinventoryfunctions.h + * @brief Miscellaneous inventory-related functions and classes + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINVENTORYFUNCTIONS_H +#define LL_LLINVENTORYFUNCTIONS_H + +#include "llassetstorage.h" +#include "lldarray.h" +#include "llfloater.h" +#include "llinventory.h" +#include "llinventoryfilter.h" +#include "llfolderview.h" +#include "llinventorymodel.h" +#include "lluictrlfactory.h" +#include <set> + + +class LLFolderViewItem; +class LLInventoryFilter; +class LLInventoryModel; +class LLInventoryPanel; +class LLInvFVBridge; +class LLInventoryFVBridgeBuilder; +class LLMenuBarGL; +class LLCheckBoxCtrl; +class LLSpinCtrl; +class LLScrollContainer; +class LLTextBox; +class LLIconCtrl; +class LLSaveFolderState; +class LLFilterEditor; +class LLTabContainer; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// This is a collection of miscellaneous functions and classes +// that don't fit cleanly into any other class header. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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 +}; + +class LLSelectFirstFilteredItem : public LLFolderViewFunctor +{ +public: + LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} + virtual ~LLSelectFirstFilteredItem() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); + BOOL wasItemSelected() { return mItemSelected; } +protected: + BOOL mItemSelected; +}; + +class LLOpenFilteredFolders : public LLFolderViewFunctor +{ +public: + LLOpenFilteredFolders() {} + virtual ~LLOpenFilteredFolders() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +class LLSaveFolderState : public LLFolderViewFunctor +{ +public: + LLSaveFolderState() : mApply(FALSE) {} + virtual ~LLSaveFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + void setApply(BOOL apply); + void clearOpenFolders() { mOpenFolders.clear(); } +protected: + std::set<LLUUID> mOpenFolders; + BOOL mApply; +}; + +class LLOpenFoldersWithSelection : public LLFolderViewFunctor +{ +public: + LLOpenFoldersWithSelection() {} + virtual ~LLOpenFoldersWithSelection() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +const std::string& get_item_icon_name(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ); + +LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ); + +#endif // LL_LLINVENTORYFUNCTIONS_H + + + diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index c17a035503b661a5a833f6ef71662fa3abec19e9..d1ca0efed35962196cdf67040e3863eaa60c4034 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1,888 +1,888 @@ -/** - * @file llfloaterinventory.cpp - * @brief Implementation of the inventory view and associated stuff. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include <utility> // for std::pair<> - -#include "llinventorypanel.h" - -// Seraph TODO: Remove unnecessary headers - -// library includes -#include "llagent.h" -#include "llagentwearables.h" -#include "llcallingcard.h" -#include "llfloaterreg.h" -#include "llsdserialize.h" -#include "llfiltereditor.h" -#include "llspinctrl.h" -#include "llui.h" -#include "message.h" - -// newview includes -#include "llappearancemgr.h" -#include "llappviewer.h" -#include "llfirstuse.h" -#include "llfloaterchat.h" -#include "llfloatercustomize.h" -#include "llfocusmgr.h" -#include "llfolderview.h" -#include "llgesturemgr.h" -#include "lliconctrl.h" -#include "llimview.h" -#include "llinventorybridge.h" -#include "llinventoryclipboard.h" -#include "llinventorymodel.h" -#include "lllineeditor.h" -#include "llmenugl.h" -#include "llpreviewanim.h" -#include "llpreviewgesture.h" -#include "llpreviewnotecard.h" -#include "llpreviewscript.h" -#include "llpreviewsound.h" -#include "llpreviewtexture.h" -#include "llresmgr.h" -#include "llscrollbar.h" -#include "llscrollcontainer.h" -#include "llselectmgr.h" -#include "lltabcontainer.h" -#include "lltooldraganddrop.h" -#include "lluictrlfactory.h" -#include "llviewerinventory.h" -#include "llviewermessage.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llwearablelist.h" - -static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel"); - -const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); -const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); -const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); -static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; - -LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : - LLPanel(p), - mInventoryObserver(NULL), - mFolders(NULL), - mScroller(NULL), - mSortOrderSetting(p.sort_order_setting), - mInventory(p.inventory), - mAllowMultiSelect(p.allow_multi_select), - mHasInventoryConnection(false), - mStartFolderString(p.start_folder), - mBuildDefaultHierarchy(true), - mInvFVBridgeBuilder(NULL) -{ - mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; - - // contex menu callbacks - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); - mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); - mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); - - setBackgroundColor(LLUIColorTable::instance().getColor("InventoryBackgroundColor")); - setBackgroundVisible(TRUE); - setBackgroundOpaque(TRUE); -} - -BOOL LLInventoryPanel::postBuild() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD); - - mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves - - // create root folder - { - LLRect folder_rect(0, - 0, - getRect().getWidth(), - 0); - LLFolderView::Params p; - p.name = getName(); - p.rect = folder_rect; - p.parent_panel = this; - mFolders = LLUICtrlFactory::create<LLFolderView>(p); - mFolders->setAllowMultiSelect(mAllowMultiSelect); - } - - mCommitCallbackRegistrar.popScope(); - - mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); - - // scroller - { - LLRect scroller_view_rect = getRect(); - scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); - LLScrollContainer::Params p; - p.name("Inventory Scroller"); - p.rect(scroller_view_rect); - p.follows.flags(FOLLOWS_ALL); - p.reserve_scroll_corner(true); - p.tab_stop(true); - mScroller = LLUICtrlFactory::create<LLScrollContainer>(p); - } - addChild(mScroller); - mScroller->addChild(mFolders); - - mFolders->setScrollContainer(mScroller); - - // set up the callbacks from the inventory we're viewing, and then - // build everything. - mInventoryObserver = new LLInventoryPanelObserver(this); - mInventory->addObserver(mInventoryObserver); - - // determine the root folder, if any, so inventory contents show just the children - // of that folder (i.e. not including the folder itself). - const LLAssetType::EType preferred_type = LLAssetType::lookupHumanReadable(mStartFolderString); - - if ("inventory" == mStartFolderString) - { - mStartFolderID = gInventory.getRootFolderID(); - } - else if ("library" == mStartFolderString) - { - mStartFolderID = gInventory.getLibraryRootFolderID(); - } - else - { - mStartFolderID = (preferred_type != LLAssetType::AT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null); - } - - // build view of inventory if we need default full hierarchy and inventory ready, otherwise wait for modelChanged() callback - if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mHasInventoryConnection) - { - rebuildViewsFor(mStartFolderID); - mHasInventoryConnection = true; - } - - // bit of a hack to make sure the inventory is open. - mFolders->openFolder(preferred_type != LLAssetType::AT_NONE ? LLAssetType::lookupCategoryName(preferred_type) : "My Inventory"); - - if (mSortOrderSetting != INHERIT_SORT_ORDER) - { - setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); - } - else - { - setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); - } - mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); - - return TRUE; -} - -LLInventoryPanel::~LLInventoryPanel() -{ - // should this be a global setting? - if (mFolders) - { - U32 sort_order = mFolders->getSortOrder(); - if (mSortOrderSetting != INHERIT_SORT_ORDER) - { - gSavedSettings.setU32(mSortOrderSetting, sort_order); - } - } - - // LLView destructor will take care of the sub-views. - mInventory->removeObserver(mInventoryObserver); - delete mInventoryObserver; - mScroller = NULL; -} - -LLMemType mt(LLMemType::MTYPE_INVENTORY_FROM_XML); // ! BUG ! Should this be removed? -void LLInventoryPanel::draw() -{ - // select the desired item (in case it wasn't loaded when the selection was requested) - mFolders->updateSelection(); - LLPanel::draw(); -} - -LLInventoryFilter* LLInventoryPanel::getFilter() -{ - if (mFolders) return mFolders->getFilter(); - return NULL; -} - -void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories) -{ - mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories); -} - -void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) -{ - mFolders->getFilter()->setFilterPermissions(filter_perm_mask); -} - -void LLInventoryPanel::setFilterSubString(const std::string& string) -{ - mFolders->getFilter()->setFilterSubString(string); -} - -void LLInventoryPanel::setSortOrder(U32 order) -{ - mFolders->getFilter()->setSortOrder(order); - if (mFolders->getFilter()->isModified()) - { - mFolders->setSortOrder(order); - // try to keep selection onscreen, even if it wasn't to start with - mFolders->scrollToShowSelection(); - } -} - -void LLInventoryPanel::setSinceLogoff(BOOL sl) -{ - mFolders->getFilter()->setDateRangeLastLogoff(sl); -} - -void LLInventoryPanel::setHoursAgo(U32 hours) -{ - mFolders->getFilter()->setHoursAgo(hours); -} - -void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) -{ - mFolders->getFilter()->setShowFolderState(show); -} - -LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() -{ - return mFolders->getFilter()->getShowFolderState(); -} - -static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); - -void LLInventoryPanel::modelChanged(U32 mask) -{ - LLFastTimer t2(FTM_REFRESH); - - bool handled = false; - - // inventory just initialized, do complete build - if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection) - { - rebuildViewsFor(mStartFolderID); - mHasInventoryConnection = true; - return; - } - - if(mask & LLInventoryObserver::LABEL) - { - handled = true; - // label change - empty out the display name for each object - // in this change set. - const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); - std::set<LLUUID>::const_iterator id_it = changed_items.begin(); - std::set<LLUUID>::const_iterator id_end = changed_items.end(); - LLFolderViewItem* view = NULL; - LLInvFVBridge* bridge = NULL; - for (;id_it != id_end; ++id_it) - { - view = mFolders->getItemByID(*id_it); - if(view) - { - // request refresh on this item (also flags for filtering) - bridge = (LLInvFVBridge*)view->getListener(); - if(bridge) - { // Clear the display name first, so it gets properly re-built during refresh() - bridge->clearDisplayName(); - } - view->refresh(); - } - } - } - if((mask & (LLInventoryObserver::STRUCTURE - | LLInventoryObserver::ADD - | LLInventoryObserver::REMOVE)) != 0) - { - handled = true; - // Record which folders are open by uuid. - LLInventoryModel* model = getModel(); - if (model) - { - const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); - - std::set<LLUUID>::const_iterator id_it = changed_items.begin(); - std::set<LLUUID>::const_iterator id_end = changed_items.end(); - for (;id_it != id_end; ++id_it) - { - // sync view with model - LLInventoryObject* model_item = model->getObject(*id_it); - LLFolderViewItem* view_item = mFolders->getItemByID(*id_it); - - if (model_item) - { - if (!view_item) - { - // this object was just created, need to build a view for it - if ((mask & LLInventoryObserver::ADD) != LLInventoryObserver::ADD) - { - llwarns << *id_it << " is in model but not in view, but ADD flag not set" << llendl; - } - buildNewViews(*id_it); - - // select any newly created object - // that has the auto rename at top of folder - // root set - if(mFolders->getRoot()->needsAutoRename()) - { - setSelection(*id_it, FALSE); - } - } - else - { - // this object was probably moved, check its parent - if ((mask & LLInventoryObserver::STRUCTURE) != LLInventoryObserver::STRUCTURE) - { - llwarns << *id_it << " is in model and in view, but STRUCTURE flag not set" << llendl; - } - - LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); - - // added check against NULL for cases when Inventory panel contains startFolder. - // in this case parent is LLFolderView (LLInventoryPanel::mFolders) itself. - // this check is a fix for bug EXT-1859. - if (NULL != new_parent && view_item->getParentFolder() != new_parent) - { - view_item->getParentFolder()->extractItem(view_item); - view_item->addToFolder(new_parent, mFolders); - } - } - } - else - { - if (view_item) - { - if ((mask & LLInventoryObserver::REMOVE) != LLInventoryObserver::REMOVE) - { - llwarns << *id_it << " is not in model but in view, but REMOVE flag not set" << llendl; - } - // item in view but not model, need to delete view - view_item->destroyView(); - } - else - { - llwarns << *id_it << "Item does not exist in either view or model, but notification triggered" << llendl; - } - } - } - } - } - - if (!handled) - { - // it's a small change that only requires a refresh. - // *TODO: figure out a more efficient way to do the refresh - // since it is expensive on large inventories - mFolders->refresh(); - } -} - - -void LLInventoryPanel::rebuildViewsFor(const LLUUID& id) -{ - LLFolderViewItem* old_view = NULL; - - // get old LLFolderViewItem - old_view = mFolders->getItemByID(id); - if (old_view && id.notNull()) - { - old_view->destroyView(); - } - - buildNewViews(id); -} - -void LLInventoryPanel::buildNewViews(const LLUUID& id) -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS); - LLFolderViewItem* itemp = NULL; - LLInventoryObject* objectp = NULL; - - // Don't add the start folder (the inventory panel will show contents - // beginning with the children of the starting folder, excluding the starting folder itself). - if (id != mStartFolderID) - { - objectp = gInventory.getObject(id); - if (objectp) - { - const LLUUID &parent_id = objectp->getParentUUID(); - // If this item's parent is the starting folder, then just add it to the top level (recall that - // the starting folder isn't actually represented in the view, parent_folder would be NULL in - // this case otherwise). - LLFolderViewFolder* parent_folder = (parent_id == mStartFolderID ? - mFolders : (LLFolderViewFolder*)mFolders->getItemByID(parent_id)); - - // This item exists outside the inventory's hierarchy, so don't add it. - if (!parent_folder) - { - return; - } - - if (objectp->getType() <= LLAssetType::AT_NONE || - objectp->getType() >= LLAssetType::AT_COUNT) - { - llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " << - ((S32) objectp->getType()) << llendl; - return; - } - - if (objectp->getType() == LLAssetType::AT_CATEGORY && - objectp->getActualType() != LLAssetType::AT_LINK_FOLDER) - { - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), - objectp->getType(), - LLInventoryType::IT_CATEGORY, - this, - objectp->getUUID()); - - if (new_listener) - { - LLFolderViewFolder::Params p; - p.name = new_listener->getDisplayName(); - p.icon = new_listener->getIcon(); - p.root = mFolders; - p.listener = new_listener; - LLFolderViewFolder* folderp = LLUICtrlFactory::create<LLFolderViewFolder>(p); - - folderp->setItemSortOrder(mFolders->getSortOrder()); - itemp = folderp; - } - } - else - { - // Build new view for item - LLInventoryItem* item = (LLInventoryItem*)objectp; - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), - item->getActualType(), - item->getInventoryType(), - this, - item->getUUID(), - item->getFlags()); - - if (new_listener) - { - LLFolderViewItem::Params params; - params.name(new_listener->getDisplayName()); - params.icon(new_listener->getIcon()); - params.creation_date(new_listener->getCreationDate()); - params.root(mFolders); - params.listener(new_listener); - params.rect(LLRect (0, 0, 0, 0)); - itemp = LLUICtrlFactory::create<LLFolderViewItem> (params); - } - } - - if (itemp) - { - itemp->addToFolder(parent_folder, mFolders); - } - } - } - - // If this is a folder, add the children of the folder and recursively add any - // child folders. - if ((id == mStartFolderID) || - (objectp && objectp->getType() == LLAssetType::AT_CATEGORY)) - { - LLViewerInventoryCategory::cat_array_t* categories; - LLViewerInventoryItem::item_array_t* items; - - mInventory->lockDirectDescendentArrays(id, categories, items); - if(categories) - { - S32 count = categories->count(); - for(S32 i = 0; i < count; ++i) - { - LLInventoryCategory* cat = categories->get(i); - buildNewViews(cat->getUUID()); - } - } - if(items) - { - S32 count = items->count(); - for(S32 i = 0; i < count; ++i) - { - LLInventoryItem* item = items->get(i); - buildNewViews(item->getUUID()); - } - } - mInventory->unlockDirectDescendentArrays(id); - } -} - -struct LLConfirmPurgeData -{ - LLUUID mID; - LLInventoryModel* mModel; -}; - -class LLIsNotWorn : public LLInventoryCollectFunctor -{ -public: - LLIsNotWorn() {} - virtual ~LLIsNotWorn() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - return !gAgentWearables.isWearingItem(item->getUUID()); - } -}; - -class LLOpenFolderByID : public LLFolderViewFunctor -{ -public: - LLOpenFolderByID(const LLUUID& id) : mID(id) {} - virtual ~LLOpenFolderByID() {} - virtual void doFolder(LLFolderViewFolder* folder) - { - if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - virtual void doItem(LLFolderViewItem* item) {} -protected: - const LLUUID& mID; -}; - - -void LLInventoryPanel::openSelected() -{ - LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); - if(!folder_item) return; - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); - if(!bridge) return; - bridge->openItem(); -} - -BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) -{ - BOOL handled = LLView::handleHover(x, y, mask); - if(handled) - { - ECursorType cursor = getWindow()->getCursor(); - if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) - { - // replace arrow cursor with arrow and hourglass cursor - getWindow()->setCursor(UI_CURSOR_WORKING); - } - } - else - { - getWindow()->setCursor(UI_CURSOR_ARROW); - } - return TRUE; -} - -BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - - BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - - if (handled) - { - mFolders->setDragAndDropThisFrame(); - } - - return handled; -} - -void LLInventoryPanel::onFocusLost() -{ - // inventory no longer handles cut/copy/paste/delete - if (LLEditMenuHandler::gEditMenuHandler == mFolders) - { - LLEditMenuHandler::gEditMenuHandler = NULL; - } - - LLPanel::onFocusLost(); -} - -void LLInventoryPanel::onFocusReceived() -{ - // inventory now handles cut/copy/paste/delete - LLEditMenuHandler::gEditMenuHandler = mFolders; - - LLPanel::onFocusReceived(); -} - - -void LLInventoryPanel::openAllFolders() -{ - mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); - mFolders->arrangeAll(); -} - -void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) -{ - LLUUID category_id = mInventory->findCategoryUUIDForType(type); - LLOpenFolderByID opener(category_id); - mFolders->applyFunctorRecursively(opener); -} - -void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) -{ - // Don't select objects in COF (e.g. to prevent refocus when items are worn). - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (obj && obj->getParentUUID() == LLAppearanceManager::getCOF()) - { - return; - } - mFolders->setSelectionByID(obj_id, take_keyboard_focus); -} - -void LLInventoryPanel::clearSelection() -{ - mFolders->clearSelection(); -} - -void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action) -{ - LLFolderView* fv = getRootFolder(); - if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename - { - fv->setNeedsAutoRename(FALSE); - if (items.size()) // new asset is visible and selected - { - fv->startRenamingSelectedItem(); - } - } - // Seraph - Put determineFolderType in here for ensemble typing? -} - -//---------------------------------------------------------------------------- - -void LLInventoryPanel::doToSelected(const LLSD& userdata) -{ - mFolders->doToSelected(&gInventory, userdata); -} - -void LLInventoryPanel::doCreate(const LLSD& userdata) -{ - menu_create_inventory_item(mFolders, LLFolderBridge::sSelf, userdata); -} - -bool LLInventoryPanel::beginIMSession() -{ - std::set<LLUUID> selected_items; - mFolders->getSelectionList(selected_items); - - std::string name; - static int session_num = 1; - - LLDynamicArray<LLUUID> members; - EInstantMessage type = IM_SESSION_CONFERENCE_START; - - std::set<LLUUID>::const_iterator iter; - for (iter = selected_items.begin(); iter != selected_items.end(); iter++) - { - - LLUUID item = *iter; - LLFolderViewItem* folder_item = mFolders->getItemByID(item); - - if(folder_item) - { - LLFolderViewEventListener* fve_listener = folder_item->getListener(); - if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) - { - - LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener(); - if(!bridge) return true; - LLViewerInventoryCategory* cat = bridge->getCategory(); - if(!cat) return true; - name = cat->getName(); - LLUniqueBuddyCollector is_buddy; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendentsIf(bridge->getUUID(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_buddy); - S32 count = item_array.count(); - if(count > 0) - { - LLFloaterReg::showInstance("communicate"); - // create the session - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLUUID id; - for(S32 i = 0; i < count; ++i) - { - id = item_array.get(i)->getCreatorUUID(); - if(at.isBuddyOnline(id)) - { - members.put(id); - } - } - } - } - else - { - LLFolderViewItem* folder_item = mFolders->getItemByID(item); - if(!folder_item) return true; - LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener(); - - if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) - { - LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID()); - - if (inv_item) - { - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLUUID id = inv_item->getCreatorUUID(); - - if(at.isBuddyOnline(id)) - { - members.put(id); - } - } - } //if IT_CALLINGCARD - } //if !IT_CATEGORY - } - } //for selected_items - - // the session_id is randomly generated UUID which will be replaced later - // with a server side generated number - - if (name.empty()) - { - name = llformat("Session %d", session_num++); - } - - gIMMgr->addSession(name, type, members[0], members); - - return true; -} - -bool LLInventoryPanel::attachObject(const LLSD& userdata) -{ - std::set<LLUUID> selected_items; - mFolders->getSelectionList(selected_items); - - std::string joint_name = userdata.asString(); - LLVOAvatar *avatarp = static_cast<LLVOAvatar*>(gAgent.getAvatarObject()); - LLViewerJointAttachment* attachmentp = NULL; - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getName() == joint_name) - { - attachmentp = attachment; - break; - } - } - if (attachmentp == NULL) - { - return true; - } - - for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin(); - set_iter != selected_items.end(); - ++set_iter) - { - const LLUUID &id = *set_iter; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); - if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - rez_attachment(item, attachmentp); - } - else if(item && item->isComplete()) - { - // must be in library. copy it to our inventory and put it on. - LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp); - copy_inventory_item(gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - } - gFocusMgr.setKeyboardFocus(NULL); - - return true; -} - - -//---------------------------------------------------------------------------- - -// static DEBUG ONLY: -void LLInventoryPanel::dumpSelectionInformation(void* user_data) -{ - LLInventoryPanel* iv = (LLInventoryPanel*)user_data; - iv->mFolders->dumpSelectionInformation(); -} - -BOOL LLInventoryPanel::getSinceLogoff() -{ - return mFolders->getFilter()->isSinceLogoff(); -} - -void example_param_block_usage() -{ - LLInventoryPanel::Params param_block; - param_block.name(std::string("inventory")); - - param_block.sort_order_setting(LLInventoryPanel::RECENTITEMS_SORT_ORDER); - param_block.allow_multi_select(true); - param_block.filter(LLInventoryPanel::Filter() - .sort_order(1) - .types(0xffff0000)); - param_block.inventory(&gInventory); - param_block.has_border(true); - - LLUICtrlFactory::create<LLInventoryPanel>(param_block); - - param_block = LLInventoryPanel::Params(); - param_block.name(std::string("inventory")); - - //LLSD param_block_sd; - //param_block_sd["sort_order_setting"] = LLInventoryPanel::RECENTITEMS_SORT_ORDER; - //param_block_sd["allow_multi_select"] = true; - //param_block_sd["filter"]["sort_order"] = 1; - //param_block_sd["filter"]["types"] = (S32)0xffff0000; - //param_block_sd["has_border"] = true; - - //LLInitParam::LLSDParser(param_block_sd).parse(param_block); - - LLUICtrlFactory::create<LLInventoryPanel>(param_block); -} +/** + * @file llfloaterinventory.cpp + * @brief Implementation of the inventory view and associated stuff. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include <utility> // for std::pair<> + +#include "llinventorypanel.h" + +// Seraph TODO: Remove unnecessary headers + +// library includes +#include "llagent.h" +#include "llagentwearables.h" +#include "llcallingcard.h" +#include "llfloaterreg.h" +#include "llsdserialize.h" +#include "llfiltereditor.h" +#include "llspinctrl.h" +#include "llui.h" +#include "message.h" + +// newview includes +#include "llappearancemgr.h" +#include "llappviewer.h" +#include "llfirstuse.h" +#include "llfloaterchat.h" +#include "llfloatercustomize.h" +#include "llfocusmgr.h" +#include "llfolderview.h" +#include "llgesturemgr.h" +#include "lliconctrl.h" +#include "llimview.h" +#include "llinventorybridge.h" +#include "llinventoryclipboard.h" +#include "llinventorymodel.h" +#include "lllineeditor.h" +#include "llmenugl.h" +#include "llpreviewanim.h" +#include "llpreviewgesture.h" +#include "llpreviewnotecard.h" +#include "llpreviewscript.h" +#include "llpreviewsound.h" +#include "llpreviewtexture.h" +#include "llresmgr.h" +#include "llscrollbar.h" +#include "llscrollcontainer.h" +#include "llselectmgr.h" +#include "lltabcontainer.h" +#include "lltooldraganddrop.h" +#include "lluictrlfactory.h" +#include "llviewerinventory.h" +#include "llviewermessage.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwearablelist.h" + +static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel"); + +const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); +const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); +const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); +static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; + +LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : + LLPanel(p), + mInventoryObserver(NULL), + mFolders(NULL), + mScroller(NULL), + mSortOrderSetting(p.sort_order_setting), + mInventory(p.inventory), + mAllowMultiSelect(p.allow_multi_select), + mHasInventoryConnection(false), + mStartFolderString(p.start_folder), + mBuildDefaultHierarchy(true), + mInvFVBridgeBuilder(NULL) +{ + mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; + + // contex menu callbacks + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); + mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); + + setBackgroundColor(LLUIColorTable::instance().getColor("InventoryBackgroundColor")); + setBackgroundVisible(TRUE); + setBackgroundOpaque(TRUE); +} + +BOOL LLInventoryPanel::postBuild() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD); + + mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves + + // create root folder + { + LLRect folder_rect(0, + 0, + getRect().getWidth(), + 0); + LLFolderView::Params p; + p.name = getName(); + p.rect = folder_rect; + p.parent_panel = this; + mFolders = LLUICtrlFactory::create<LLFolderView>(p); + mFolders->setAllowMultiSelect(mAllowMultiSelect); + } + + mCommitCallbackRegistrar.popScope(); + + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); + + // scroller + { + LLRect scroller_view_rect = getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params p; + p.name("Inventory Scroller"); + p.rect(scroller_view_rect); + p.follows.flags(FOLLOWS_ALL); + p.reserve_scroll_corner(true); + p.tab_stop(true); + mScroller = LLUICtrlFactory::create<LLScrollContainer>(p); + } + addChild(mScroller); + mScroller->addChild(mFolders); + + mFolders->setScrollContainer(mScroller); + + // set up the callbacks from the inventory we're viewing, and then + // build everything. + mInventoryObserver = new LLInventoryPanelObserver(this); + mInventory->addObserver(mInventoryObserver); + + // determine the root folder, if any, so inventory contents show just the children + // of that folder (i.e. not including the folder itself). + const LLAssetType::EType preferred_type = LLAssetType::lookupHumanReadable(mStartFolderString); + + if ("inventory" == mStartFolderString) + { + mStartFolderID = gInventory.getRootFolderID(); + } + else if ("library" == mStartFolderString) + { + mStartFolderID = gInventory.getLibraryRootFolderID(); + } + else + { + mStartFolderID = (preferred_type != LLAssetType::AT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null); + } + + // build view of inventory if we need default full hierarchy and inventory ready, otherwise wait for modelChanged() callback + if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mHasInventoryConnection) + { + rebuildViewsFor(mStartFolderID); + mHasInventoryConnection = true; + } + + // bit of a hack to make sure the inventory is open. + mFolders->openFolder(preferred_type != LLAssetType::AT_NONE ? LLAssetType::lookupCategoryName(preferred_type) : "My Inventory"); + + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); + } + else + { + setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); + } + mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); + + return TRUE; +} + +LLInventoryPanel::~LLInventoryPanel() +{ + // should this be a global setting? + if (mFolders) + { + U32 sort_order = mFolders->getSortOrder(); + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + gSavedSettings.setU32(mSortOrderSetting, sort_order); + } + } + + // LLView destructor will take care of the sub-views. + mInventory->removeObserver(mInventoryObserver); + delete mInventoryObserver; + mScroller = NULL; +} + +LLMemType mt(LLMemType::MTYPE_INVENTORY_FROM_XML); // ! BUG ! Should this be removed? +void LLInventoryPanel::draw() +{ + // select the desired item (in case it wasn't loaded when the selection was requested) + mFolders->updateSelection(); + LLPanel::draw(); +} + +LLInventoryFilter* LLInventoryPanel::getFilter() +{ + if (mFolders) return mFolders->getFilter(); + return NULL; +} + +void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories) +{ + mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories); +} + +void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) +{ + mFolders->getFilter()->setFilterPermissions(filter_perm_mask); +} + +void LLInventoryPanel::setFilterSubString(const std::string& string) +{ + mFolders->getFilter()->setFilterSubString(string); +} + +void LLInventoryPanel::setSortOrder(U32 order) +{ + mFolders->getFilter()->setSortOrder(order); + if (mFolders->getFilter()->isModified()) + { + mFolders->setSortOrder(order); + // try to keep selection onscreen, even if it wasn't to start with + mFolders->scrollToShowSelection(); + } +} + +void LLInventoryPanel::setSinceLogoff(BOOL sl) +{ + mFolders->getFilter()->setDateRangeLastLogoff(sl); +} + +void LLInventoryPanel::setHoursAgo(U32 hours) +{ + mFolders->getFilter()->setHoursAgo(hours); +} + +void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) +{ + mFolders->getFilter()->setShowFolderState(show); +} + +LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() +{ + return mFolders->getFilter()->getShowFolderState(); +} + +static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); + +void LLInventoryPanel::modelChanged(U32 mask) +{ + LLFastTimer t2(FTM_REFRESH); + + bool handled = false; + + // inventory just initialized, do complete build + if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection) + { + rebuildViewsFor(mStartFolderID); + mHasInventoryConnection = true; + return; + } + + if(mask & LLInventoryObserver::LABEL) + { + handled = true; + // label change - empty out the display name for each object + // in this change set. + const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); + std::set<LLUUID>::const_iterator id_it = changed_items.begin(); + std::set<LLUUID>::const_iterator id_end = changed_items.end(); + LLFolderViewItem* view = NULL; + LLInvFVBridge* bridge = NULL; + for (;id_it != id_end; ++id_it) + { + view = mFolders->getItemByID(*id_it); + if(view) + { + // request refresh on this item (also flags for filtering) + bridge = (LLInvFVBridge*)view->getListener(); + if(bridge) + { // Clear the display name first, so it gets properly re-built during refresh() + bridge->clearDisplayName(); + } + view->refresh(); + } + } + } + if((mask & (LLInventoryObserver::STRUCTURE + | LLInventoryObserver::ADD + | LLInventoryObserver::REMOVE)) != 0) + { + handled = true; + // Record which folders are open by uuid. + LLInventoryModel* model = getModel(); + if (model) + { + const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); + + std::set<LLUUID>::const_iterator id_it = changed_items.begin(); + std::set<LLUUID>::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + // sync view with model + LLInventoryObject* model_item = model->getObject(*id_it); + LLFolderViewItem* view_item = mFolders->getItemByID(*id_it); + + if (model_item) + { + if (!view_item) + { + // this object was just created, need to build a view for it + if ((mask & LLInventoryObserver::ADD) != LLInventoryObserver::ADD) + { + llwarns << *id_it << " is in model but not in view, but ADD flag not set" << llendl; + } + buildNewViews(*id_it); + + // select any newly created object + // that has the auto rename at top of folder + // root set + if(mFolders->getRoot()->needsAutoRename()) + { + setSelection(*id_it, FALSE); + } + } + else + { + // this object was probably moved, check its parent + if ((mask & LLInventoryObserver::STRUCTURE) != LLInventoryObserver::STRUCTURE) + { + llwarns << *id_it << " is in model and in view, but STRUCTURE flag not set" << llendl; + } + + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); + + // added check against NULL for cases when Inventory panel contains startFolder. + // in this case parent is LLFolderView (LLInventoryPanel::mFolders) itself. + // this check is a fix for bug EXT-1859. + if (NULL != new_parent && view_item->getParentFolder() != new_parent) + { + view_item->getParentFolder()->extractItem(view_item); + view_item->addToFolder(new_parent, mFolders); + } + } + } + else + { + if (view_item) + { + if ((mask & LLInventoryObserver::REMOVE) != LLInventoryObserver::REMOVE) + { + llwarns << *id_it << " is not in model but in view, but REMOVE flag not set" << llendl; + } + // item in view but not model, need to delete view + view_item->destroyView(); + } + else + { + llwarns << *id_it << "Item does not exist in either view or model, but notification triggered" << llendl; + } + } + } + } + } + + if (!handled) + { + // it's a small change that only requires a refresh. + // *TODO: figure out a more efficient way to do the refresh + // since it is expensive on large inventories + mFolders->refresh(); + } +} + + +void LLInventoryPanel::rebuildViewsFor(const LLUUID& id) +{ + LLFolderViewItem* old_view = NULL; + + // get old LLFolderViewItem + old_view = mFolders->getItemByID(id); + if (old_view && id.notNull()) + { + old_view->destroyView(); + } + + buildNewViews(id); +} + +void LLInventoryPanel::buildNewViews(const LLUUID& id) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS); + LLFolderViewItem* itemp = NULL; + LLInventoryObject* objectp = NULL; + + // Don't add the start folder (the inventory panel will show contents + // beginning with the children of the starting folder, excluding the starting folder itself). + if (id != mStartFolderID) + { + objectp = gInventory.getObject(id); + if (objectp) + { + const LLUUID &parent_id = objectp->getParentUUID(); + // If this item's parent is the starting folder, then just add it to the top level (recall that + // the starting folder isn't actually represented in the view, parent_folder would be NULL in + // this case otherwise). + LLFolderViewFolder* parent_folder = (parent_id == mStartFolderID ? + mFolders : (LLFolderViewFolder*)mFolders->getItemByID(parent_id)); + + // This item exists outside the inventory's hierarchy, so don't add it. + if (!parent_folder) + { + return; + } + + if (objectp->getType() <= LLAssetType::AT_NONE || + objectp->getType() >= LLAssetType::AT_COUNT) + { + llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " << + ((S32) objectp->getType()) << llendl; + return; + } + + if (objectp->getType() == LLAssetType::AT_CATEGORY && + objectp->getActualType() != LLAssetType::AT_LINK_FOLDER) + { + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), + objectp->getType(), + LLInventoryType::IT_CATEGORY, + this, + objectp->getUUID()); + + if (new_listener) + { + LLFolderViewFolder::Params p; + p.name = new_listener->getDisplayName(); + p.icon = new_listener->getIcon(); + p.root = mFolders; + p.listener = new_listener; + LLFolderViewFolder* folderp = LLUICtrlFactory::create<LLFolderViewFolder>(p); + + folderp->setItemSortOrder(mFolders->getSortOrder()); + itemp = folderp; + } + } + else + { + // Build new view for item + LLInventoryItem* item = (LLInventoryItem*)objectp; + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), + item->getActualType(), + item->getInventoryType(), + this, + item->getUUID(), + item->getFlags()); + + if (new_listener) + { + LLFolderViewItem::Params params; + params.name(new_listener->getDisplayName()); + params.icon(new_listener->getIcon()); + params.creation_date(new_listener->getCreationDate()); + params.root(mFolders); + params.listener(new_listener); + params.rect(LLRect (0, 0, 0, 0)); + itemp = LLUICtrlFactory::create<LLFolderViewItem> (params); + } + } + + if (itemp) + { + itemp->addToFolder(parent_folder, mFolders); + } + } + } + + // If this is a folder, add the children of the folder and recursively add any + // child folders. + if ((id == mStartFolderID) || + (objectp && objectp->getType() == LLAssetType::AT_CATEGORY)) + { + LLViewerInventoryCategory::cat_array_t* categories; + LLViewerInventoryItem::item_array_t* items; + + mInventory->lockDirectDescendentArrays(id, categories, items); + if(categories) + { + S32 count = categories->count(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryCategory* cat = categories->get(i); + buildNewViews(cat->getUUID()); + } + } + if(items) + { + S32 count = items->count(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryItem* item = items->get(i); + buildNewViews(item->getUUID()); + } + } + mInventory->unlockDirectDescendentArrays(id); + } +} + +struct LLConfirmPurgeData +{ + LLUUID mID; + LLInventoryModel* mModel; +}; + +class LLIsNotWorn : public LLInventoryCollectFunctor +{ +public: + LLIsNotWorn() {} + virtual ~LLIsNotWorn() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + return !gAgentWearables.isWearingItem(item->getUUID()); + } +}; + +class LLOpenFolderByID : public LLFolderViewFunctor +{ +public: + LLOpenFolderByID(const LLUUID& id) : mID(id) {} + virtual ~LLOpenFolderByID() {} + virtual void doFolder(LLFolderViewFolder* folder) + { + if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + virtual void doItem(LLFolderViewItem* item) {} +protected: + const LLUUID& mID; +}; + + +void LLInventoryPanel::openSelected() +{ + LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); + if(!folder_item) return; + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); + if(!bridge) return; + bridge->openItem(); +} + +BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleHover(x, y, mask); + if(handled) + { + ECursorType cursor = getWindow()->getCursor(); + if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + { + // replace arrow cursor with arrow and hourglass cursor + getWindow()->setCursor(UI_CURSOR_WORKING); + } + } + else + { + getWindow()->setCursor(UI_CURSOR_ARROW); + } + return TRUE; +} + +BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + + BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + if (handled) + { + mFolders->setDragAndDropThisFrame(); + } + + return handled; +} + +void LLInventoryPanel::onFocusLost() +{ + // inventory no longer handles cut/copy/paste/delete + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + + LLPanel::onFocusLost(); +} + +void LLInventoryPanel::onFocusReceived() +{ + // inventory now handles cut/copy/paste/delete + LLEditMenuHandler::gEditMenuHandler = mFolders; + + LLPanel::onFocusReceived(); +} + + +void LLInventoryPanel::openAllFolders() +{ + mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolders->arrangeAll(); +} + +void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) +{ + LLUUID category_id = mInventory->findCategoryUUIDForType(type); + LLOpenFolderByID opener(category_id); + mFolders->applyFunctorRecursively(opener); +} + +void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + // Don't select objects in COF (e.g. to prevent refocus when items are worn). + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == LLAppearanceManager::getCOF()) + { + return; + } + mFolders->setSelectionByID(obj_id, take_keyboard_focus); +} + +void LLInventoryPanel::clearSelection() +{ + mFolders->clearSelection(); +} + +void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action) +{ + LLFolderView* fv = getRootFolder(); + if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename + { + fv->setNeedsAutoRename(FALSE); + if (items.size()) // new asset is visible and selected + { + fv->startRenamingSelectedItem(); + } + } + // Seraph - Put determineFolderType in here for ensemble typing? +} + +//---------------------------------------------------------------------------- + +void LLInventoryPanel::doToSelected(const LLSD& userdata) +{ + mFolders->doToSelected(&gInventory, userdata); +} + +void LLInventoryPanel::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(mFolders, LLFolderBridge::sSelf, userdata); +} + +bool LLInventoryPanel::beginIMSession() +{ + std::set<LLUUID> selected_items; + mFolders->getSelectionList(selected_items); + + std::string name; + static int session_num = 1; + + LLDynamicArray<LLUUID> members; + EInstantMessage type = IM_SESSION_CONFERENCE_START; + + std::set<LLUUID>::const_iterator iter; + for (iter = selected_items.begin(); iter != selected_items.end(); iter++) + { + + LLUUID item = *iter; + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + + if(folder_item) + { + LLFolderViewEventListener* fve_listener = folder_item->getListener(); + if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) + { + + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener(); + if(!bridge) return true; + LLViewerInventoryCategory* cat = bridge->getCategory(); + if(!cat) return true; + name = cat->getName(); + LLUniqueBuddyCollector is_buddy; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendentsIf(bridge->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_buddy); + S32 count = item_array.count(); + if(count > 0) + { + LLFloaterReg::showInstance("communicate"); + // create the session + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id; + for(S32 i = 0; i < count; ++i) + { + id = item_array.get(i)->getCreatorUUID(); + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } + } + else + { + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + if(!folder_item) return true; + LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener(); + + if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) + { + LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID()); + + if (inv_item) + { + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id = inv_item->getCreatorUUID(); + + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } //if IT_CALLINGCARD + } //if !IT_CATEGORY + } + } //for selected_items + + // the session_id is randomly generated UUID which will be replaced later + // with a server side generated number + + if (name.empty()) + { + name = llformat("Session %d", session_num++); + } + + gIMMgr->addSession(name, type, members[0], members); + + return true; +} + +bool LLInventoryPanel::attachObject(const LLSD& userdata) +{ + std::set<LLUUID> selected_items; + mFolders->getSelectionList(selected_items); + + std::string joint_name = userdata.asString(); + LLVOAvatar *avatarp = static_cast<LLVOAvatar*>(gAgent.getAvatarObject()); + LLViewerJointAttachment* attachmentp = NULL; + for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); + iter != avatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getName() == joint_name) + { + attachmentp = attachment; + break; + } + } + if (attachmentp == NULL) + { + return true; + } + + for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin(); + set_iter != selected_items.end(); + ++set_iter) + { + const LLUUID &id = *set_iter; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); + if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + rez_attachment(item, attachmentp); + } + else if(item && item->isComplete()) + { + // must be in library. copy it to our inventory and put it on. + LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp); + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + } + gFocusMgr.setKeyboardFocus(NULL); + + return true; +} + + +//---------------------------------------------------------------------------- + +// static DEBUG ONLY: +void LLInventoryPanel::dumpSelectionInformation(void* user_data) +{ + LLInventoryPanel* iv = (LLInventoryPanel*)user_data; + iv->mFolders->dumpSelectionInformation(); +} + +BOOL LLInventoryPanel::getSinceLogoff() +{ + return mFolders->getFilter()->isSinceLogoff(); +} + +void example_param_block_usage() +{ + LLInventoryPanel::Params param_block; + param_block.name(std::string("inventory")); + + param_block.sort_order_setting(LLInventoryPanel::RECENTITEMS_SORT_ORDER); + param_block.allow_multi_select(true); + param_block.filter(LLInventoryPanel::Filter() + .sort_order(1) + .types(0xffff0000)); + param_block.inventory(&gInventory); + param_block.has_border(true); + + LLUICtrlFactory::create<LLInventoryPanel>(param_block); + + param_block = LLInventoryPanel::Params(); + param_block.name(std::string("inventory")); + + //LLSD param_block_sd; + //param_block_sd["sort_order_setting"] = LLInventoryPanel::RECENTITEMS_SORT_ORDER; + //param_block_sd["allow_multi_select"] = true; + //param_block_sd["filter"]["sort_order"] = 1; + //param_block_sd["filter"]["types"] = (S32)0xffff0000; + //param_block_sd["has_border"] = true; + + //LLInitParam::LLSDParser(param_block_sd).parse(param_block); + + LLUICtrlFactory::create<LLInventoryPanel>(param_block); +} diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index f958aaf839d2360b956735fc994c1782a4281fc5..997678a478478da94a44fcfbfdb65e515b276176 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -1,206 +1,206 @@ -/** - * @file llinventorypanel.h - * @brief LLInventoryPanel - * class definition - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLINVENTORYPANEL_H -#define LL_LLINVENTORYPANEL_H - -#include "llassetstorage.h" -#include "lldarray.h" -#include "llfloater.h" -#include "llinventory.h" -#include "llinventoryfilter.h" -#include "llfolderview.h" -#include "llinventorymodel.h" -#include "lluictrlfactory.h" -#include <set> - -class LLFolderViewItem; -class LLInventoryFilter; -class LLInventoryModel; -class LLInvFVBridge; -class LLInventoryFVBridgeBuilder; -class LLMenuBarGL; -class LLCheckBoxCtrl; -class LLSpinCtrl; -class LLScrollContainer; -class LLTextBox; -class LLIconCtrl; -class LLSaveFolderState; -class LLFilterEditor; -class LLTabContainer; - -class LLInventoryPanel : public LLPanel -{ -public: - static const std::string DEFAULT_SORT_ORDER; - static const std::string RECENTITEMS_SORT_ORDER; - static const std::string INHERIT_SORT_ORDER; - - struct Filter : public LLInitParam::Block<Filter> - { - Optional<U32> sort_order; - Optional<U32> types; - Optional<std::string> search_string; - - Filter() - : sort_order("sort_order"), - types("types", 0xffffffff), - search_string("search_string") - {} - }; - - struct Params - : public LLInitParam::Block<Params, LLPanel::Params> - { - Optional<std::string> sort_order_setting; - Optional<LLInventoryModel*> inventory; - Optional<bool> allow_multi_select; - Optional<Filter> filter; - Optional<std::string> start_folder; - - Params() - : sort_order_setting("sort_order_setting"), - inventory("", &gInventory), - allow_multi_select("allow_multi_select", true), - filter("filter"), - start_folder("start_folder") - {} - }; - -protected: - LLInventoryPanel(const Params&); - friend class LLUICtrlFactory; - -public: - virtual ~LLInventoryPanel(); - - LLInventoryModel* getModel() { return mInventory; } - - BOOL postBuild(); - - // LLView methods - void draw(); - BOOL handleHover(S32 x, S32 y, MASK mask); - BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - // LLUICtrl methods - /*virtual*/ void onFocusLost(); - /*virtual*/ void onFocusReceived(); - - // Call this method to set the selection. - void openAllFolders(); - void openDefaultFolderForType(LLAssetType::EType); - void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); - void setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { if (mFolders) mFolders->setSelectCallback(cb); } - void clearSelection(); - LLInventoryFilter* getFilter(); - void setFilterTypes(U64 filter, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type - U32 getFilterTypes() const { return mFolders->getFilterTypes(); } - void setFilterPermMask(PermissionMask filter_perm_mask); - U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); } - void setFilterSubString(const std::string& string); - const std::string getFilterSubString() { return mFolders->getFilterSubString(); } - void setSortOrder(U32 order); - U32 getSortOrder() { return mFolders->getSortOrder(); } - void setSinceLogoff(BOOL sl); - void setHoursAgo(U32 hours); - BOOL getSinceLogoff(); - - void setShowFolderState(LLInventoryFilter::EFolderShow show); - LLInventoryFilter::EFolderShow getShowFolderState(); - void setAllowMultiSelect(BOOL allow) { mFolders->setAllowMultiSelect(allow); } - // This method is called when something has changed about the inventory. - void modelChanged(U32 mask); - LLFolderView* getRootFolder() { return mFolders; } - LLScrollContainer* getScrollableContainer() { return mScroller; } - - void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); - - // Callbacks - void doToSelected(const LLSD& userdata); - void doCreate(const LLSD& userdata); - bool beginIMSession(); - bool attachObject(const LLSD& userdata); - - // DEBUG ONLY: - static void dumpSelectionInformation(void* user_data); - - void openSelected(); - void unSelectAll() { mFolders->setSelection(NULL, FALSE, FALSE); } - -protected: - // Given the id and the parent, build all of the folder views. - void rebuildViewsFor(const LLUUID& id); - virtual void buildNewViews(const LLUUID& id); // made virtual to support derived classes. EXT-719 - -protected: - LLInventoryModel* mInventory; - LLInventoryObserver* mInventoryObserver; - BOOL mAllowMultiSelect; - std::string mSortOrderSetting; - -//private: // Can not make these private - needed by llinventorysubtreepanel - LLFolderView* mFolders; - std::string mStartFolderString; - - /** - * Contains UUID of Inventory item from which hierarchy should be built. - * Can be set with the "start_folder" xml property. - * Default is LLUUID::null that means total Inventory hierarchy. - */ - LLUUID mStartFolderID; - LLScrollContainer* mScroller; - bool mHasInventoryConnection; - - /** - * Flag specified if default inventory hierarchy should be created in postBuild() - */ - bool mBuildDefaultHierarchy; - - LLUUID mRootInventoryItemUUID; - - /** - * Pointer to LLInventoryFVBridgeBuilder. - * - * It is set in LLInventoryPanel's constructor and can be overridden in derived classes with - * another implementation. - * Take into account it will not be deleted by LLInventoryPanel itself. - */ - const LLInventoryFVBridgeBuilder* mInvFVBridgeBuilder; - -}; - -#endif // LL_LLINVENTORYPANEL_H +/** + * @file llinventorypanel.h + * @brief LLInventoryPanel + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINVENTORYPANEL_H +#define LL_LLINVENTORYPANEL_H + +#include "llassetstorage.h" +#include "lldarray.h" +#include "llfloater.h" +#include "llinventory.h" +#include "llinventoryfilter.h" +#include "llfolderview.h" +#include "llinventorymodel.h" +#include "lluictrlfactory.h" +#include <set> + +class LLFolderViewItem; +class LLInventoryFilter; +class LLInventoryModel; +class LLInvFVBridge; +class LLInventoryFVBridgeBuilder; +class LLMenuBarGL; +class LLCheckBoxCtrl; +class LLSpinCtrl; +class LLScrollContainer; +class LLTextBox; +class LLIconCtrl; +class LLSaveFolderState; +class LLFilterEditor; +class LLTabContainer; + +class LLInventoryPanel : public LLPanel +{ +public: + static const std::string DEFAULT_SORT_ORDER; + static const std::string RECENTITEMS_SORT_ORDER; + static const std::string INHERIT_SORT_ORDER; + + struct Filter : public LLInitParam::Block<Filter> + { + Optional<U32> sort_order; + Optional<U32> types; + Optional<std::string> search_string; + + Filter() + : sort_order("sort_order"), + types("types", 0xffffffff), + search_string("search_string") + {} + }; + + struct Params + : public LLInitParam::Block<Params, LLPanel::Params> + { + Optional<std::string> sort_order_setting; + Optional<LLInventoryModel*> inventory; + Optional<bool> allow_multi_select; + Optional<Filter> filter; + Optional<std::string> start_folder; + + Params() + : sort_order_setting("sort_order_setting"), + inventory("", &gInventory), + allow_multi_select("allow_multi_select", true), + filter("filter"), + start_folder("start_folder") + {} + }; + +protected: + LLInventoryPanel(const Params&); + friend class LLUICtrlFactory; + +public: + virtual ~LLInventoryPanel(); + + LLInventoryModel* getModel() { return mInventory; } + + BOOL postBuild(); + + // LLView methods + void draw(); + BOOL handleHover(S32 x, S32 y, MASK mask); + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + // LLUICtrl methods + /*virtual*/ void onFocusLost(); + /*virtual*/ void onFocusReceived(); + + // Call this method to set the selection. + void openAllFolders(); + void openDefaultFolderForType(LLAssetType::EType); + void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); + void setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { if (mFolders) mFolders->setSelectCallback(cb); } + void clearSelection(); + LLInventoryFilter* getFilter(); + void setFilterTypes(U64 filter, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type + U32 getFilterTypes() const { return mFolders->getFilterTypes(); } + void setFilterPermMask(PermissionMask filter_perm_mask); + U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); } + void setFilterSubString(const std::string& string); + const std::string getFilterSubString() { return mFolders->getFilterSubString(); } + void setSortOrder(U32 order); + U32 getSortOrder() { return mFolders->getSortOrder(); } + void setSinceLogoff(BOOL sl); + void setHoursAgo(U32 hours); + BOOL getSinceLogoff(); + + void setShowFolderState(LLInventoryFilter::EFolderShow show); + LLInventoryFilter::EFolderShow getShowFolderState(); + void setAllowMultiSelect(BOOL allow) { mFolders->setAllowMultiSelect(allow); } + // This method is called when something has changed about the inventory. + void modelChanged(U32 mask); + LLFolderView* getRootFolder() { return mFolders; } + LLScrollContainer* getScrollableContainer() { return mScroller; } + + void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); + + // Callbacks + void doToSelected(const LLSD& userdata); + void doCreate(const LLSD& userdata); + bool beginIMSession(); + bool attachObject(const LLSD& userdata); + + // DEBUG ONLY: + static void dumpSelectionInformation(void* user_data); + + void openSelected(); + void unSelectAll() { mFolders->setSelection(NULL, FALSE, FALSE); } + +protected: + // Given the id and the parent, build all of the folder views. + void rebuildViewsFor(const LLUUID& id); + virtual void buildNewViews(const LLUUID& id); // made virtual to support derived classes. EXT-719 + +protected: + LLInventoryModel* mInventory; + LLInventoryObserver* mInventoryObserver; + BOOL mAllowMultiSelect; + std::string mSortOrderSetting; + +//private: // Can not make these private - needed by llinventorysubtreepanel + LLFolderView* mFolders; + std::string mStartFolderString; + + /** + * Contains UUID of Inventory item from which hierarchy should be built. + * Can be set with the "start_folder" xml property. + * Default is LLUUID::null that means total Inventory hierarchy. + */ + LLUUID mStartFolderID; + LLScrollContainer* mScroller; + bool mHasInventoryConnection; + + /** + * Flag specified if default inventory hierarchy should be created in postBuild() + */ + bool mBuildDefaultHierarchy; + + LLUUID mRootInventoryItemUUID; + + /** + * Pointer to LLInventoryFVBridgeBuilder. + * + * It is set in LLInventoryPanel's constructor and can be overridden in derived classes with + * another implementation. + * Take into account it will not be deleted by LLInventoryPanel itself. + */ + const LLInventoryFVBridgeBuilder* mInvFVBridgeBuilder; + +}; + +#endif // LL_LLINVENTORYPANEL_H diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index ca567018e7a029ca1e11b8dba7c49d7f527d528d..617445a27f2da506e00d71a46bdb22c8f0fc973d 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -1,818 +1,818 @@ -/** - * @file llsidepanelmaininventory.cpp - * @brief Implementation of llsidepanelmaininventory. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llpanelmaininventory.h" - -#include "llfloaterinventory.h" -#include "llinventorybridge.h" -#include "llinventoryfunctions.h" -#include "llinventorypanel.h" -#include "llfiltereditor.h" -#include "llfloaterreg.h" -#include "llscrollcontainer.h" -#include "llsdserialize.h" -#include "llspinctrl.h" -#include "lltooldraganddrop.h" - -static LLRegisterPanelClassWrapper<LLPanelMainInventory> t_inventory("panel_main_inventory"); // Seraph is this redundant with constructor? - -///---------------------------------------------------------------------------- -/// LLFloaterInventoryFinder -///---------------------------------------------------------------------------- - -class LLFloaterInventoryFinder : public LLFloater -{ -public: - LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view); - virtual void draw(); - /*virtual*/ BOOL postBuild(); - void changeFilter(LLInventoryFilter* filter); - void updateElementsFromFilter(); - BOOL getCheckShowEmpty(); - BOOL getCheckSinceLogoff(); - - static void onTimeAgo(LLUICtrl*, void *); - static void onCheckSinceLogoff(LLUICtrl*, void *); - static void onCloseBtn(void* user_data); - static void selectAllTypes(void* user_data); - static void selectNoTypes(void* user_data); -private: - LLPanelMainInventory* mPanelInventoryDecorated; - LLSpinCtrl* mSpinSinceDays; - LLSpinCtrl* mSpinSinceHours; - LLInventoryFilter* mFilter; -}; - -///---------------------------------------------------------------------------- -/// LLPanelMainInventory -///---------------------------------------------------------------------------- - -LLPanelMainInventory::LLPanelMainInventory() - : LLPanel() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_INIT); - // Menu Callbacks (non contex menus) - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLPanelMainInventory::closeAllFolders, this)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2)); - mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow, this)); - mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this)); - mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this)); - mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2)); - - // Controls - // *TODO: Just use persistant settings for each of these - U32 sort_order = gSavedSettings.getU32("InventorySortOrder"); - BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE ); - BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME ); - BOOL sort_system_folders_to_top = ( sort_order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ); - - gSavedSettings.declareBOOL("Inventory.SortByName", sort_by_name, "Declared in code", FALSE); - gSavedSettings.declareBOOL("Inventory.SortByDate", !sort_by_name, "Declared in code", FALSE); - gSavedSettings.declareBOOL("Inventory.FoldersAlwaysByName", sort_folders_by_name, "Declared in code", FALSE); - gSavedSettings.declareBOOL("Inventory.SystemFoldersToTop", sort_system_folders_to_top, "Declared in code", FALSE); - - mSavedFolderState = new LLSaveFolderState(); - mSavedFolderState->setApply(FALSE); -} - -BOOL LLPanelMainInventory::postBuild() -{ - gInventory.addObserver(this); - - mFilterTabs = getChild<LLTabContainer>("inventory filter tabs"); - mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this)); - - //panel->getFilter()->markDefault(); - - // Set up the default inv. panel/filter settings. - mActivePanel = getChild<LLInventoryPanel>("All Items"); - if (mActivePanel) - { - // "All Items" is the previous only view, so it gets the InventorySortOrder - mActivePanel->setSortOrder(gSavedSettings.getU32("InventorySortOrder")); - mActivePanel->getFilter()->markDefault(); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - mActivePanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mActivePanel, _1, _2)); - } - LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items"); - if (recent_items_panel) - { - recent_items_panel->setSinceLogoff(TRUE); - recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); - recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - recent_items_panel->getFilter()->markDefault(); - recent_items_panel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, recent_items_panel, _1, _2)); - } - - // Now load the stored settings from disk, if available. - std::ostringstream filterSaveName; - filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); - llinfos << "LLPanelMainInventory::init: reading from " << filterSaveName << llendl; - llifstream file(filterSaveName.str()); - LLSD savedFilterState; - if (file.is_open()) - { - LLSDSerialize::fromXML(savedFilterState, file); - file.close(); - - // Load the persistent "Recent Items" settings. - // Note that the "All Items" settings do not persist. - if(recent_items_panel) - { - if(savedFilterState.has(recent_items_panel->getFilter()->getName())) - { - LLSD recent_items = savedFilterState.get( - recent_items_panel->getFilter()->getName()); - recent_items_panel->getFilter()->fromLLSD(recent_items); - } - } - - } - - - mFilterEditor = getChild<LLFilterEditor>("inventory search editor"); - if (mFilterEditor) - { - mFilterEditor->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterEdit, this, _2)); - } - - // *TODO:Get the cost info from the server - const std::string upload_cost("10"); - childSetLabelArg("Upload Image", "[COST]", upload_cost); - childSetLabelArg("Upload Sound", "[COST]", upload_cost); - childSetLabelArg("Upload Animation", "[COST]", upload_cost); - childSetLabelArg("Bulk Upload", "[COST]", upload_cost); - - return TRUE; -} - -// Destroys the object -LLPanelMainInventory::~LLPanelMainInventory( void ) -{ - // Save the filters state. - LLSD filterRoot; - LLInventoryPanel* all_items_panel = getChild<LLInventoryPanel>("All Items"); - if (all_items_panel) - { - LLInventoryFilter* filter = all_items_panel->getFilter(); - if (filter) - { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; - } - } - - LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items"); - if (recent_items_panel) - { - LLInventoryFilter* filter = recent_items_panel->getFilter(); - if (filter) - { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; - } - } - - std::ostringstream filterSaveName; - filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); - llofstream filtersFile(filterSaveName.str()); - if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile)) - { - llwarns << "Could not write to filters save file " << filterSaveName << llendl; - } - else - filtersFile.close(); - - gInventory.removeObserver(this); - delete mSavedFolderState; -} - -void LLPanelMainInventory::startSearch() -{ - // this forces focus to line editor portion of search editor - if (mFilterEditor) - { - mFilterEditor->focusFirstItem(TRUE); - } -} - -BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask) -{ - LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; - if (root_folder) - { - // first check for user accepting current search results - if (mFilterEditor - && mFilterEditor->hasFocus() - && (key == KEY_RETURN - || key == KEY_DOWN) - && mask == MASK_NONE) - { - // move focus to inventory proper - mActivePanel->setFocus(TRUE); - root_folder->scrollToShowSelection(); - return TRUE; - } - - if (mActivePanel->hasFocus() && key == KEY_UP) - { - startSearch(); - } - } - - return LLPanel::handleKeyHere(key, mask); - -} - -//---------------------------------------------------------------------------- -// menu callbacks - -void LLPanelMainInventory::doToSelected(const LLSD& userdata) -{ - getPanel()->getRootFolder()->doToSelected(&gInventory, userdata); -} - -void LLPanelMainInventory::closeAllFolders() -{ - getPanel()->getRootFolder()->closeAllFolders(); -} - -void LLPanelMainInventory::newWindow() -{ - LLFloaterInventory::showAgentInventory(); -} - -void LLPanelMainInventory::doCreate(const LLSD& userdata) -{ - menu_create_inventory_item(getPanel()->getRootFolder(), NULL, userdata); -} - -void LLPanelMainInventory::resetFilters() -{ - LLFloaterInventoryFinder *finder = getFinder(); - getActivePanel()->getFilter()->resetDefault(); - if (finder) - { - finder->updateElementsFromFilter(); - } - - setFilterTextFromFilter(); -} - -void LLPanelMainInventory::setSortBy(const LLSD& userdata) -{ - std::string sort_field = userdata.asString(); - if (sort_field == "name") - { - U32 order = getActivePanel()->getSortOrder(); - getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); - - gSavedSettings.setBOOL("Inventory.SortByName", TRUE ); - gSavedSettings.setBOOL("Inventory.SortByDate", FALSE ); - } - else if (sort_field == "date") - { - U32 order = getActivePanel()->getSortOrder(); - getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE ); - - gSavedSettings.setBOOL("Inventory.SortByName", FALSE ); - gSavedSettings.setBOOL("Inventory.SortByDate", TRUE ); - } - else if (sort_field == "foldersalwaysbyname") - { - U32 order = getActivePanel()->getSortOrder(); - if ( order & LLInventoryFilter::SO_FOLDERS_BY_NAME ) - { - order &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME; - - gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", FALSE ); - } - else - { - order |= LLInventoryFilter::SO_FOLDERS_BY_NAME; - - gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", TRUE ); - } - getActivePanel()->setSortOrder( order ); - } - else if (sort_field == "systemfolderstotop") - { - U32 order = getActivePanel()->getSortOrder(); - if ( order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ) - { - order &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; - - gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", FALSE ); - } - else - { - order |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; - - gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE ); - } - getActivePanel()->setSortOrder( order ); - } -} - -// static -BOOL LLPanelMainInventory::filtersVisible(void* user_data) -{ - LLPanelMainInventory* self = (LLPanelMainInventory*)user_data; - if(!self) return FALSE; - - return self->getFinder() != NULL; -} - -void LLPanelMainInventory::onClearSearch() -{ - LLFloater *finder = getFinder(); - if (mActivePanel) - { - mActivePanel->setFilterSubString(LLStringUtil::null); - mActivePanel->setFilterTypes(0xffffffff); - } - - if (finder) - { - LLFloaterInventoryFinder::selectAllTypes(finder); - } - - // re-open folders that were initially open - if (mActivePanel) - { - mSavedFolderState->setApply(TRUE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - LLOpenFoldersWithSelection opener; - mActivePanel->getRootFolder()->applyFunctorRecursively(opener); - mActivePanel->getRootFolder()->scrollToShowSelection(); - } -} - -void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) -{ - if (search_string == "") - { - onClearSearch(); - } - if (!mActivePanel) - { - return; - } - - gInventory.startBackgroundFetch(); - - std::string uppercase_search_string = search_string; - LLStringUtil::toUpper(uppercase_search_string); - if (mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) - { - // current filter and new filter empty, do nothing - return; - } - - // save current folder open state if no filter currently applied - if (!mActivePanel->getRootFolder()->isFilterModified()) - { - mSavedFolderState->setApply(FALSE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - } - - // set new filter string - mActivePanel->setFilterSubString(uppercase_search_string); -} - - - //static - BOOL LLPanelMainInventory::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) - { - LLPanelMainInventory* active_view = NULL; - - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); - for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) - { - LLPanelMainInventory* iv = dynamic_cast<LLPanelMainInventory*>(*iter); - if (iv) - { - if (gFocusMgr.childHasKeyboardFocus(iv)) - { - active_view = iv; - break; - } - } - } - - if (!active_view) - { - return FALSE; - } - - std::string search_string(find_text); - - if (search_string.empty()) - { - return FALSE; - } - - if (active_view->getPanel() && - active_view->getPanel()->getRootFolder()->search(first_item, search_string, backward)) - { - return TRUE; - } - - return FALSE; - } - -void LLPanelMainInventory::onFilterSelected() -{ - // Find my index - mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); - - if (!mActivePanel) - { - return; - } - LLInventoryFilter* filter = mActivePanel->getFilter(); - LLFloaterInventoryFinder *finder = getFinder(); - if (finder) - { - finder->changeFilter(filter); - } - if (filter->isActive()) - { - // If our filter is active we may be the first thing requiring a fetch so we better start it here. - gInventory.startBackgroundFetch(); - } - setFilterTextFromFilter(); -} - -const std::string LLPanelMainInventory::getFilterSubString() -{ - return mActivePanel->getFilterSubString(); -} - -void LLPanelMainInventory::setFilterSubString(const std::string& string) -{ - mActivePanel->setFilterSubString(string); -} - -BOOL LLPanelMainInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - // Check to see if we are auto scrolling from the last frame - LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel(); - BOOL needsToScroll = panel->getScrollableContainer()->autoScroll(x, y); - if(mFilterTabs) - { - if(needsToScroll) - { - mFilterTabs->startDragAndDropDelayTimer(); - } - } - - BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - - return handled; -} - -void LLPanelMainInventory::changed(U32 mask) -{ -} - - -void LLPanelMainInventory::setFilterTextFromFilter() -{ - mFilterText = mActivePanel->getFilter()->getFilterText(); -} - -void LLPanelMainInventory::toggleFindOptions() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE); - LLFloater *floater = getFinder(); - if (!floater) - { - LLFloaterInventoryFinder * finder = new LLFloaterInventoryFinder(this); - mFinderHandle = finder->getHandle(); - finder->openFloater(); - - LLFloater* parent_floater = gFloaterView->getParentFloater(this); - if (parent_floater) // Seraph: Fix this, shouldn't be null even for sidepanel - parent_floater->addDependentFloater(mFinderHandle); - // start background fetch of folders - gInventory.startBackgroundFetch(); - } - else - { - floater->closeFloater(); - } -} - -void LLPanelMainInventory::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) -{ - getChild<LLInventoryPanel>("All Items")->setSelectCallback(cb); - getChild<LLInventoryPanel>("Recent Items")->setSelectCallback(cb); -} - -///---------------------------------------------------------------------------- -/// LLFloaterInventoryFinder -///---------------------------------------------------------------------------- - -LLFloaterInventoryFinder* LLPanelMainInventory::getFinder() -{ - return (LLFloaterInventoryFinder*)mFinderHandle.get(); -} - - -LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view) : - LLFloater(LLSD()), - mPanelInventoryDecorated(inventory_view), - mFilter(inventory_view->getPanel()->getFilter()) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml", NULL); - updateElementsFromFilter(); -} - - -void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data) -{ - LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; - if (!self) return; - - bool since_logoff= self->childGetValue("check_since_logoff"); - - if (!since_logoff && - !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) ) - { - self->mSpinSinceHours->set(1.0f); - } -} -BOOL LLFloaterInventoryFinder::postBuild() -{ - const LLRect& viewrect = mPanelInventoryDecorated->getRect(); - setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); - - childSetAction("All", selectAllTypes, this); - childSetAction("None", selectNoTypes, this); - - mSpinSinceHours = getChild<LLSpinCtrl>("spin_hours_ago"); - childSetCommitCallback("spin_hours_ago", onTimeAgo, this); - - mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago"); - childSetCommitCallback("spin_days_ago", onTimeAgo, this); - - // mCheckSinceLogoff = getChild<LLSpinCtrl>("check_since_logoff"); - childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this); - - childSetAction("Close", onCloseBtn, this); - - updateElementsFromFilter(); - return TRUE; -} -void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) -{ - LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; - if (!self) return; - - bool since_logoff=true; - if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) - { - since_logoff = false; - } - self->childSetValue("check_since_logoff", since_logoff); -} - -void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter) -{ - mFilter = filter; - updateElementsFromFilter(); -} - -void LLFloaterInventoryFinder::updateElementsFromFilter() -{ - if (!mFilter) - return; - - // Get data needed for filter display - U32 filter_types = mFilter->getFilterTypes(); - std::string filter_string = mFilter->getFilterSubString(); - LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); - U32 hours = mFilter->getHoursAgo(); - - // update the ui elements - setTitle(mFilter->getName()); - - childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); - - childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); - childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); - childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); - childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); - childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); - childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); - childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); - childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); - childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); - childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); - childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); - childSetValue("check_since_logoff", mFilter->isSinceLogoff()); - mSpinSinceHours->set((F32)(hours % 24)); - mSpinSinceDays->set((F32)(hours / 24)); -} - -void LLFloaterInventoryFinder::draw() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_DRAW); - U32 filter = 0xffffffff; - BOOL filtered_by_all_types = TRUE; - - if (!childGetValue("check_animation")) - { - filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); - filtered_by_all_types = FALSE; - } - - - if (!childGetValue("check_calling_card")) - { - filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_clothing")) - { - filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_gesture")) - { - filter &= ~(0x1 << LLInventoryType::IT_GESTURE); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_landmark")) - - - { - filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_notecard")) - { - filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_object")) - { - filter &= ~(0x1 << LLInventoryType::IT_OBJECT); - filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_script")) - { - filter &= ~(0x1 << LLInventoryType::IT_LSL); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_sound")) - { - filter &= ~(0x1 << LLInventoryType::IT_SOUND); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_texture")) - { - filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_snapshot")) - { - filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); - filtered_by_all_types = FALSE; - } - - if (!filtered_by_all_types) - { - // don't include folders in filter, unless I've selected everything - filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); - } - - // update the panel, panel will update the filter - mPanelInventoryDecorated->getPanel()->setShowFolderState(getCheckShowEmpty() ? - LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mPanelInventoryDecorated->getPanel()->setFilterTypes(filter); - if (getCheckSinceLogoff()) - { - mSpinSinceDays->set(0); - mSpinSinceHours->set(0); - } - U32 days = (U32)mSpinSinceDays->get(); - U32 hours = (U32)mSpinSinceHours->get(); - if (hours > 24) - { - days += hours / 24; - hours = (U32)hours % 24; - mSpinSinceDays->set((F32)days); - mSpinSinceHours->set((F32)hours); - } - hours += days * 24; - mPanelInventoryDecorated->getPanel()->setHoursAgo(hours); - mPanelInventoryDecorated->getPanel()->setSinceLogoff(getCheckSinceLogoff()); - mPanelInventoryDecorated->setFilterTextFromFilter(); - - LLPanel::draw(); -} - -BOOL LLFloaterInventoryFinder::getCheckShowEmpty() -{ - return childGetValue("check_show_empty"); -} - -BOOL LLFloaterInventoryFinder::getCheckSinceLogoff() -{ - return childGetValue("check_since_logoff"); -} - -void LLFloaterInventoryFinder::onCloseBtn(void* user_data) -{ - LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; - finderp->closeFloater(); -} - -// static -void LLFloaterInventoryFinder::selectAllTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - self->childSetValue("check_animation", TRUE); - self->childSetValue("check_calling_card", TRUE); - self->childSetValue("check_clothing", TRUE); - self->childSetValue("check_gesture", TRUE); - self->childSetValue("check_landmark", TRUE); - self->childSetValue("check_notecard", TRUE); - self->childSetValue("check_object", TRUE); - self->childSetValue("check_script", TRUE); - self->childSetValue("check_sound", TRUE); - self->childSetValue("check_texture", TRUE); - self->childSetValue("check_snapshot", TRUE); -} - -//static -void LLFloaterInventoryFinder::selectNoTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - self->childSetValue("check_animation", FALSE); - self->childSetValue("check_calling_card", FALSE); - self->childSetValue("check_clothing", FALSE); - self->childSetValue("check_gesture", FALSE); - self->childSetValue("check_landmark", FALSE); - self->childSetValue("check_notecard", FALSE); - self->childSetValue("check_object", FALSE); - self->childSetValue("check_script", FALSE); - self->childSetValue("check_sound", FALSE); - self->childSetValue("check_texture", FALSE); - self->childSetValue("check_snapshot", FALSE); -} +/** + * @file llsidepanelmaininventory.cpp + * @brief Implementation of llsidepanelmaininventory. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llpanelmaininventory.h" + +#include "llfloaterinventory.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" +#include "llfiltereditor.h" +#include "llfloaterreg.h" +#include "llscrollcontainer.h" +#include "llsdserialize.h" +#include "llspinctrl.h" +#include "lltooldraganddrop.h" + +static LLRegisterPanelClassWrapper<LLPanelMainInventory> t_inventory("panel_main_inventory"); // Seraph is this redundant with constructor? + +///---------------------------------------------------------------------------- +/// LLFloaterInventoryFinder +///---------------------------------------------------------------------------- + +class LLFloaterInventoryFinder : public LLFloater +{ +public: + LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view); + virtual void draw(); + /*virtual*/ BOOL postBuild(); + void changeFilter(LLInventoryFilter* filter); + void updateElementsFromFilter(); + BOOL getCheckShowEmpty(); + BOOL getCheckSinceLogoff(); + + static void onTimeAgo(LLUICtrl*, void *); + static void onCheckSinceLogoff(LLUICtrl*, void *); + static void onCloseBtn(void* user_data); + static void selectAllTypes(void* user_data); + static void selectNoTypes(void* user_data); +private: + LLPanelMainInventory* mPanelInventoryDecorated; + LLSpinCtrl* mSpinSinceDays; + LLSpinCtrl* mSpinSinceHours; + LLInventoryFilter* mFilter; +}; + +///---------------------------------------------------------------------------- +/// LLPanelMainInventory +///---------------------------------------------------------------------------- + +LLPanelMainInventory::LLPanelMainInventory() + : LLPanel() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_INIT); + // Menu Callbacks (non contex menus) + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLPanelMainInventory::closeAllFolders, this)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2)); + mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow, this)); + mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this)); + mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this)); + mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2)); + + // Controls + // *TODO: Just use persistant settings for each of these + U32 sort_order = gSavedSettings.getU32("InventorySortOrder"); + BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE ); + BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME ); + BOOL sort_system_folders_to_top = ( sort_order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ); + + gSavedSettings.declareBOOL("Inventory.SortByName", sort_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.SortByDate", !sort_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.FoldersAlwaysByName", sort_folders_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.SystemFoldersToTop", sort_system_folders_to_top, "Declared in code", FALSE); + + mSavedFolderState = new LLSaveFolderState(); + mSavedFolderState->setApply(FALSE); +} + +BOOL LLPanelMainInventory::postBuild() +{ + gInventory.addObserver(this); + + mFilterTabs = getChild<LLTabContainer>("inventory filter tabs"); + mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this)); + + //panel->getFilter()->markDefault(); + + // Set up the default inv. panel/filter settings. + mActivePanel = getChild<LLInventoryPanel>("All Items"); + if (mActivePanel) + { + // "All Items" is the previous only view, so it gets the InventorySortOrder + mActivePanel->setSortOrder(gSavedSettings.getU32("InventorySortOrder")); + mActivePanel->getFilter()->markDefault(); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + mActivePanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mActivePanel, _1, _2)); + } + LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items"); + if (recent_items_panel) + { + recent_items_panel->setSinceLogoff(TRUE); + recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); + recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + recent_items_panel->getFilter()->markDefault(); + recent_items_panel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, recent_items_panel, _1, _2)); + } + + // Now load the stored settings from disk, if available. + std::ostringstream filterSaveName; + filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); + llinfos << "LLPanelMainInventory::init: reading from " << filterSaveName << llendl; + llifstream file(filterSaveName.str()); + LLSD savedFilterState; + if (file.is_open()) + { + LLSDSerialize::fromXML(savedFilterState, file); + file.close(); + + // Load the persistent "Recent Items" settings. + // Note that the "All Items" settings do not persist. + if(recent_items_panel) + { + if(savedFilterState.has(recent_items_panel->getFilter()->getName())) + { + LLSD recent_items = savedFilterState.get( + recent_items_panel->getFilter()->getName()); + recent_items_panel->getFilter()->fromLLSD(recent_items); + } + } + + } + + + mFilterEditor = getChild<LLFilterEditor>("inventory search editor"); + if (mFilterEditor) + { + mFilterEditor->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterEdit, this, _2)); + } + + // *TODO:Get the cost info from the server + const std::string upload_cost("10"); + childSetLabelArg("Upload Image", "[COST]", upload_cost); + childSetLabelArg("Upload Sound", "[COST]", upload_cost); + childSetLabelArg("Upload Animation", "[COST]", upload_cost); + childSetLabelArg("Bulk Upload", "[COST]", upload_cost); + + return TRUE; +} + +// Destroys the object +LLPanelMainInventory::~LLPanelMainInventory( void ) +{ + // Save the filters state. + LLSD filterRoot; + LLInventoryPanel* all_items_panel = getChild<LLInventoryPanel>("All Items"); + if (all_items_panel) + { + LLInventoryFilter* filter = all_items_panel->getFilter(); + if (filter) + { + LLSD filterState; + filter->toLLSD(filterState); + filterRoot[filter->getName()] = filterState; + } + } + + LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items"); + if (recent_items_panel) + { + LLInventoryFilter* filter = recent_items_panel->getFilter(); + if (filter) + { + LLSD filterState; + filter->toLLSD(filterState); + filterRoot[filter->getName()] = filterState; + } + } + + std::ostringstream filterSaveName; + filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); + llofstream filtersFile(filterSaveName.str()); + if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile)) + { + llwarns << "Could not write to filters save file " << filterSaveName << llendl; + } + else + filtersFile.close(); + + gInventory.removeObserver(this); + delete mSavedFolderState; +} + +void LLPanelMainInventory::startSearch() +{ + // this forces focus to line editor portion of search editor + if (mFilterEditor) + { + mFilterEditor->focusFirstItem(TRUE); + } +} + +BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask) +{ + LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; + if (root_folder) + { + // first check for user accepting current search results + if (mFilterEditor + && mFilterEditor->hasFocus() + && (key == KEY_RETURN + || key == KEY_DOWN) + && mask == MASK_NONE) + { + // move focus to inventory proper + mActivePanel->setFocus(TRUE); + root_folder->scrollToShowSelection(); + return TRUE; + } + + if (mActivePanel->hasFocus() && key == KEY_UP) + { + startSearch(); + } + } + + return LLPanel::handleKeyHere(key, mask); + +} + +//---------------------------------------------------------------------------- +// menu callbacks + +void LLPanelMainInventory::doToSelected(const LLSD& userdata) +{ + getPanel()->getRootFolder()->doToSelected(&gInventory, userdata); +} + +void LLPanelMainInventory::closeAllFolders() +{ + getPanel()->getRootFolder()->closeAllFolders(); +} + +void LLPanelMainInventory::newWindow() +{ + LLFloaterInventory::showAgentInventory(); +} + +void LLPanelMainInventory::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(getPanel()->getRootFolder(), NULL, userdata); +} + +void LLPanelMainInventory::resetFilters() +{ + LLFloaterInventoryFinder *finder = getFinder(); + getActivePanel()->getFilter()->resetDefault(); + if (finder) + { + finder->updateElementsFromFilter(); + } + + setFilterTextFromFilter(); +} + +void LLPanelMainInventory::setSortBy(const LLSD& userdata) +{ + std::string sort_field = userdata.asString(); + if (sort_field == "name") + { + U32 order = getActivePanel()->getSortOrder(); + getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); + + gSavedSettings.setBOOL("Inventory.SortByName", TRUE ); + gSavedSettings.setBOOL("Inventory.SortByDate", FALSE ); + } + else if (sort_field == "date") + { + U32 order = getActivePanel()->getSortOrder(); + getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE ); + + gSavedSettings.setBOOL("Inventory.SortByName", FALSE ); + gSavedSettings.setBOOL("Inventory.SortByDate", TRUE ); + } + else if (sort_field == "foldersalwaysbyname") + { + U32 order = getActivePanel()->getSortOrder(); + if ( order & LLInventoryFilter::SO_FOLDERS_BY_NAME ) + { + order &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME; + + gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", FALSE ); + } + else + { + order |= LLInventoryFilter::SO_FOLDERS_BY_NAME; + + gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", TRUE ); + } + getActivePanel()->setSortOrder( order ); + } + else if (sort_field == "systemfolderstotop") + { + U32 order = getActivePanel()->getSortOrder(); + if ( order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ) + { + order &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + + gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", FALSE ); + } + else + { + order |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + + gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE ); + } + getActivePanel()->setSortOrder( order ); + } +} + +// static +BOOL LLPanelMainInventory::filtersVisible(void* user_data) +{ + LLPanelMainInventory* self = (LLPanelMainInventory*)user_data; + if(!self) return FALSE; + + return self->getFinder() != NULL; +} + +void LLPanelMainInventory::onClearSearch() +{ + LLFloater *finder = getFinder(); + if (mActivePanel) + { + mActivePanel->setFilterSubString(LLStringUtil::null); + mActivePanel->setFilterTypes(0xffffffff); + } + + if (finder) + { + LLFloaterInventoryFinder::selectAllTypes(finder); + } + + // re-open folders that were initially open + if (mActivePanel) + { + mSavedFolderState->setApply(TRUE); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + LLOpenFoldersWithSelection opener; + mActivePanel->getRootFolder()->applyFunctorRecursively(opener); + mActivePanel->getRootFolder()->scrollToShowSelection(); + } +} + +void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) +{ + if (search_string == "") + { + onClearSearch(); + } + if (!mActivePanel) + { + return; + } + + gInventory.startBackgroundFetch(); + + std::string uppercase_search_string = search_string; + LLStringUtil::toUpper(uppercase_search_string); + if (mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) + { + // current filter and new filter empty, do nothing + return; + } + + // save current folder open state if no filter currently applied + if (!mActivePanel->getRootFolder()->isFilterModified()) + { + mSavedFolderState->setApply(FALSE); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + } + + // set new filter string + mActivePanel->setFilterSubString(uppercase_search_string); +} + + + //static + BOOL LLPanelMainInventory::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) + { + LLPanelMainInventory* active_view = NULL; + + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLPanelMainInventory* iv = dynamic_cast<LLPanelMainInventory*>(*iter); + if (iv) + { + if (gFocusMgr.childHasKeyboardFocus(iv)) + { + active_view = iv; + break; + } + } + } + + if (!active_view) + { + return FALSE; + } + + std::string search_string(find_text); + + if (search_string.empty()) + { + return FALSE; + } + + if (active_view->getPanel() && + active_view->getPanel()->getRootFolder()->search(first_item, search_string, backward)) + { + return TRUE; + } + + return FALSE; + } + +void LLPanelMainInventory::onFilterSelected() +{ + // Find my index + mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); + + if (!mActivePanel) + { + return; + } + LLInventoryFilter* filter = mActivePanel->getFilter(); + LLFloaterInventoryFinder *finder = getFinder(); + if (finder) + { + finder->changeFilter(filter); + } + if (filter->isActive()) + { + // If our filter is active we may be the first thing requiring a fetch so we better start it here. + gInventory.startBackgroundFetch(); + } + setFilterTextFromFilter(); +} + +const std::string LLPanelMainInventory::getFilterSubString() +{ + return mActivePanel->getFilterSubString(); +} + +void LLPanelMainInventory::setFilterSubString(const std::string& string) +{ + mActivePanel->setFilterSubString(string); +} + +BOOL LLPanelMainInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // Check to see if we are auto scrolling from the last frame + LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel(); + BOOL needsToScroll = panel->getScrollableContainer()->autoScroll(x, y); + if(mFilterTabs) + { + if(needsToScroll) + { + mFilterTabs->startDragAndDropDelayTimer(); + } + } + + BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + return handled; +} + +void LLPanelMainInventory::changed(U32 mask) +{ +} + + +void LLPanelMainInventory::setFilterTextFromFilter() +{ + mFilterText = mActivePanel->getFilter()->getFilterText(); +} + +void LLPanelMainInventory::toggleFindOptions() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE); + LLFloater *floater = getFinder(); + if (!floater) + { + LLFloaterInventoryFinder * finder = new LLFloaterInventoryFinder(this); + mFinderHandle = finder->getHandle(); + finder->openFloater(); + + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) // Seraph: Fix this, shouldn't be null even for sidepanel + parent_floater->addDependentFloater(mFinderHandle); + // start background fetch of folders + gInventory.startBackgroundFetch(); + } + else + { + floater->closeFloater(); + } +} + +void LLPanelMainInventory::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) +{ + getChild<LLInventoryPanel>("All Items")->setSelectCallback(cb); + getChild<LLInventoryPanel>("Recent Items")->setSelectCallback(cb); +} + +///---------------------------------------------------------------------------- +/// LLFloaterInventoryFinder +///---------------------------------------------------------------------------- + +LLFloaterInventoryFinder* LLPanelMainInventory::getFinder() +{ + return (LLFloaterInventoryFinder*)mFinderHandle.get(); +} + + +LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view) : + LLFloater(LLSD()), + mPanelInventoryDecorated(inventory_view), + mFilter(inventory_view->getPanel()->getFilter()) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml", NULL); + updateElementsFromFilter(); +} + + +void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data) +{ + LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; + if (!self) return; + + bool since_logoff= self->childGetValue("check_since_logoff"); + + if (!since_logoff && + !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) ) + { + self->mSpinSinceHours->set(1.0f); + } +} +BOOL LLFloaterInventoryFinder::postBuild() +{ + const LLRect& viewrect = mPanelInventoryDecorated->getRect(); + setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); + + childSetAction("All", selectAllTypes, this); + childSetAction("None", selectNoTypes, this); + + mSpinSinceHours = getChild<LLSpinCtrl>("spin_hours_ago"); + childSetCommitCallback("spin_hours_ago", onTimeAgo, this); + + mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago"); + childSetCommitCallback("spin_days_ago", onTimeAgo, this); + + // mCheckSinceLogoff = getChild<LLSpinCtrl>("check_since_logoff"); + childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this); + + childSetAction("Close", onCloseBtn, this); + + updateElementsFromFilter(); + return TRUE; +} +void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) +{ + LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; + if (!self) return; + + bool since_logoff=true; + if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) + { + since_logoff = false; + } + self->childSetValue("check_since_logoff", since_logoff); +} + +void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter) +{ + mFilter = filter; + updateElementsFromFilter(); +} + +void LLFloaterInventoryFinder::updateElementsFromFilter() +{ + if (!mFilter) + return; + + // Get data needed for filter display + U32 filter_types = mFilter->getFilterTypes(); + std::string filter_string = mFilter->getFilterSubString(); + LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); + U32 hours = mFilter->getHoursAgo(); + + // update the ui elements + setTitle(mFilter->getName()); + + childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); + + childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); + childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); + childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); + childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); + childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); + childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); + childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); + childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); + childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); + childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); + childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); + childSetValue("check_since_logoff", mFilter->isSinceLogoff()); + mSpinSinceHours->set((F32)(hours % 24)); + mSpinSinceDays->set((F32)(hours / 24)); +} + +void LLFloaterInventoryFinder::draw() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_DRAW); + U32 filter = 0xffffffff; + BOOL filtered_by_all_types = TRUE; + + if (!childGetValue("check_animation")) + { + filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); + filtered_by_all_types = FALSE; + } + + + if (!childGetValue("check_calling_card")) + { + filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_clothing")) + { + filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_gesture")) + { + filter &= ~(0x1 << LLInventoryType::IT_GESTURE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_landmark")) + + + { + filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_notecard")) + { + filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_object")) + { + filter &= ~(0x1 << LLInventoryType::IT_OBJECT); + filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_script")) + { + filter &= ~(0x1 << LLInventoryType::IT_LSL); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_sound")) + { + filter &= ~(0x1 << LLInventoryType::IT_SOUND); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_texture")) + { + filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_snapshot")) + { + filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); + filtered_by_all_types = FALSE; + } + + if (!filtered_by_all_types) + { + // don't include folders in filter, unless I've selected everything + filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); + } + + // update the panel, panel will update the filter + mPanelInventoryDecorated->getPanel()->setShowFolderState(getCheckShowEmpty() ? + LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mPanelInventoryDecorated->getPanel()->setFilterTypes(filter); + if (getCheckSinceLogoff()) + { + mSpinSinceDays->set(0); + mSpinSinceHours->set(0); + } + U32 days = (U32)mSpinSinceDays->get(); + U32 hours = (U32)mSpinSinceHours->get(); + if (hours > 24) + { + days += hours / 24; + hours = (U32)hours % 24; + mSpinSinceDays->set((F32)days); + mSpinSinceHours->set((F32)hours); + } + hours += days * 24; + mPanelInventoryDecorated->getPanel()->setHoursAgo(hours); + mPanelInventoryDecorated->getPanel()->setSinceLogoff(getCheckSinceLogoff()); + mPanelInventoryDecorated->setFilterTextFromFilter(); + + LLPanel::draw(); +} + +BOOL LLFloaterInventoryFinder::getCheckShowEmpty() +{ + return childGetValue("check_show_empty"); +} + +BOOL LLFloaterInventoryFinder::getCheckSinceLogoff() +{ + return childGetValue("check_since_logoff"); +} + +void LLFloaterInventoryFinder::onCloseBtn(void* user_data) +{ + LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; + finderp->closeFloater(); +} + +// static +void LLFloaterInventoryFinder::selectAllTypes(void* user_data) +{ + LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; + if(!self) return; + + self->childSetValue("check_animation", TRUE); + self->childSetValue("check_calling_card", TRUE); + self->childSetValue("check_clothing", TRUE); + self->childSetValue("check_gesture", TRUE); + self->childSetValue("check_landmark", TRUE); + self->childSetValue("check_notecard", TRUE); + self->childSetValue("check_object", TRUE); + self->childSetValue("check_script", TRUE); + self->childSetValue("check_sound", TRUE); + self->childSetValue("check_texture", TRUE); + self->childSetValue("check_snapshot", TRUE); +} + +//static +void LLFloaterInventoryFinder::selectNoTypes(void* user_data) +{ + LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; + if(!self) return; + + self->childSetValue("check_animation", FALSE); + self->childSetValue("check_calling_card", FALSE); + self->childSetValue("check_clothing", FALSE); + self->childSetValue("check_gesture", FALSE); + self->childSetValue("check_landmark", FALSE); + self->childSetValue("check_notecard", FALSE); + self->childSetValue("check_object", FALSE); + self->childSetValue("check_script", FALSE); + self->childSetValue("check_sound", FALSE); + self->childSetValue("check_texture", FALSE); + self->childSetValue("check_snapshot", FALSE); +} diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 75526a3c98f7a3438be602e53b6b3e337f1095b2..a2b988e80cb95204b6fab54b435a3e541576843b 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -1,125 +1,125 @@ -/** - * @file llpanelmaininventory.h - * @brief llpanelmaininventory.h - * class definition - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLPANELMAININVENTORY_H -#define LL_LLPANELMAININVENTORY_H - -#include "llpanel.h" -#include "llinventorymodel.h" -#include "llfolderview.h" - -class LLFolderViewItem; -class LLInventoryPanel; -class LLSaveFolderState; -class LLFilterEditor; -class LLTabContainer; -class LLFloaterInventoryFinder; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLPanelMainInventory -// -// This is a panel used to view and control an agent's inventory, -// including all the fixin's (e.g. AllItems/RecentItems tabs, filter floaters). -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLPanelMainInventory : public LLPanel, LLInventoryObserver -{ -public: - friend class LLFloaterInventoryFinder; - - LLPanelMainInventory(); - ~LLPanelMainInventory(); - - BOOL postBuild(); - - virtual BOOL handleKeyHere(KEY key, MASK mask); - - // Inherited functionality - /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - /*virtual*/ void changed(U32 mask); - - LLInventoryPanel* getPanel() { return mActivePanel; } - LLInventoryPanel* getActivePanel() { return mActivePanel; } - - const std::string& getFilterText() const { return mFilterText; } - - void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); - -protected: - // - // Misc functions - // - void setFilterTextFromFilter(); - void startSearch(); - - void toggleFindOptions(); - - static BOOL filtersVisible(void* user_data); - void onClearSearch(); - static void onFoldersByName(void *user_data); - static BOOL checkFoldersByName(void *user_data); - void onFilterEdit(const std::string& search_string ); - static BOOL incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward); - void onFilterSelected(); - - const std::string getFilterSubString(); - void setFilterSubString(const std::string& string); - - // menu callbacks - void doToSelected(const LLSD& userdata); - void closeAllFolders(); - void newWindow(); - void doCreate(const LLSD& userdata); - void resetFilters(); - void setSortBy(const LLSD& userdata); - -private: - LLFloaterInventoryFinder* getFinder(); - - LLFilterEditor* mFilterEditor; - LLTabContainer* mFilterTabs; - LLHandle<LLFloater> mFinderHandle; - LLInventoryPanel* mActivePanel; - LLSaveFolderState* mSavedFolderState; - - std::string mFilterText; -}; - -#endif // LL_LLPANELMAININVENTORY_H - - - +/** + * @file llpanelmaininventory.h + * @brief llpanelmaininventory.h + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMAININVENTORY_H +#define LL_LLPANELMAININVENTORY_H + +#include "llpanel.h" +#include "llinventorymodel.h" +#include "llfolderview.h" + +class LLFolderViewItem; +class LLInventoryPanel; +class LLSaveFolderState; +class LLFilterEditor; +class LLTabContainer; +class LLFloaterInventoryFinder; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLPanelMainInventory +// +// This is a panel used to view and control an agent's inventory, +// including all the fixin's (e.g. AllItems/RecentItems tabs, filter floaters). +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLPanelMainInventory : public LLPanel, LLInventoryObserver +{ +public: + friend class LLFloaterInventoryFinder; + + LLPanelMainInventory(); + ~LLPanelMainInventory(); + + BOOL postBuild(); + + virtual BOOL handleKeyHere(KEY key, MASK mask); + + // Inherited functionality + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + /*virtual*/ void changed(U32 mask); + + LLInventoryPanel* getPanel() { return mActivePanel; } + LLInventoryPanel* getActivePanel() { return mActivePanel; } + + const std::string& getFilterText() const { return mFilterText; } + + void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); + +protected: + // + // Misc functions + // + void setFilterTextFromFilter(); + void startSearch(); + + void toggleFindOptions(); + + static BOOL filtersVisible(void* user_data); + void onClearSearch(); + static void onFoldersByName(void *user_data); + static BOOL checkFoldersByName(void *user_data); + void onFilterEdit(const std::string& search_string ); + static BOOL incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward); + void onFilterSelected(); + + const std::string getFilterSubString(); + void setFilterSubString(const std::string& string); + + // menu callbacks + void doToSelected(const LLSD& userdata); + void closeAllFolders(); + void newWindow(); + void doCreate(const LLSD& userdata); + void resetFilters(); + void setSortBy(const LLSD& userdata); + +private: + LLFloaterInventoryFinder* getFinder(); + + LLFilterEditor* mFilterEditor; + LLTabContainer* mFilterTabs; + LLHandle<LLFloater> mFinderHandle; + LLInventoryPanel* mActivePanel; + LLSaveFolderState* mSavedFolderState; + + std::string mFilterText; +}; + +#endif // LL_LLPANELMAININVENTORY_H + + + diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index a198499b47ede597beb9122cb7e7abfe2bd49392..85efe0f93e652509fecd05147cf62c15102a8b25 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -1,453 +1,453 @@ -/** - * @file llpanelmediasettingsgeneral.cpp - * @brief LLPanelMediaSettingsGeneral class implementation - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llagent.h" -#include "llpanelmediasettingsgeneral.h" -#include "llcombobox.h" -#include "llcheckboxctrl.h" -#include "llspinctrl.h" -#include "lluictrlfactory.h" -#include "llviewerwindow.h" -#include "llviewermedia.h" -#include "llsdutil.h" -#include "llselectmgr.h" -#include "llbutton.h" -#include "lltexturectrl.h" -#include "llurl.h" -#include "llwindow.h" -#include "llmediaentry.h" -#include "llmediactrl.h" -#include "llpanelcontents.h" -#include "llpermissions.h" -#include "llpluginclassmedia.h" -#include "llfloatermediasettings.h" -#include "llfloatertools.h" -#include "lltrans.h" - -//////////////////////////////////////////////////////////////////////////////// -// -LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() : - mControls( NULL ), - mAutoLoop( NULL ), - mFirstClick( NULL ), - mAutoZoom( NULL ), - mAutoPlay( NULL ), - mAutoScale( NULL ), - mWidthPixels( NULL ), - mHeightPixels( NULL ), - mHomeURL( NULL ), - mCurrentURL( NULL ), - mParent( NULL ), - mMediaEditable(false) -{ - // build dialog from XML - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_general.xml"); -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLPanelMediaSettingsGeneral::postBuild() -{ - // connect member vars with UI widgets - mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY ); - mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY ); - mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY ); - mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY ); - mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY ); - mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY ); - mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); - mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY ); - mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY ); - mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY ); - mPreviewMedia = getChild<LLMediaCtrl>("preview_media"); - - // watch commit action for HOME URL - childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this); - childSetCommitCallback( "current_url_reset_btn",onBtnResetCurrentUrl, this); - // interrogates controls and updates widgets as required - updateMediaPreview(); - updateCurrentURL(); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsGeneral::draw() -{ - // housekeeping - LLPanel::draw(); - - // enable/disable pixel values image entry based on auto scale checkbox - if ( mAutoScale->getValue().asBoolean() == false ) - { - childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, true ); - childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, true ); - } - else - { - childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, false ); - childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, false ); - }; - - // enable/disable UI based on type of media - bool reset_button_is_active = true; - if( mPreviewMedia ) - { - LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); - if( media_plugin ) - { - // turn off volume (if we can) for preview. Note: this really only - // works for QuickTime movies right now - no way to control the - // volume of a flash app embedded in a page for example - media_plugin->setVolume( 0 ); - - // some controls are only appropriate for time or browser type plugins - // so we selectively enable/disable them - need to do it in draw - // because the information from plugins arrives assynchronously - bool show_time_controls = media_plugin->pluginSupportsMediaTime(); - if ( show_time_controls ) - { - childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, false ); - reset_button_is_active = false; - childSetEnabled( "current_url_label", false ); - childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, true ); - } - else - { - childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, true ); - reset_button_is_active = true; - childSetEnabled( "current_url_label", true ); - childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, false ); - }; - }; - }; - - // current URL can change over time. -// updateCurrentURL(); - - LLPermissions perm; - bool user_can_press_reset = mMediaEditable; - - // several places modify this widget so we must collect states in one place - if ( reset_button_is_active ) - { - // user has perms to press reset button and it is active - if ( user_can_press_reset ) - { - childSetEnabled( "current_url_reset_btn", true ); - } - // user does not has perms to press reset button and it is active - else - { - childSetEnabled( "current_url_reset_btn", false ); - }; - } - else - // reset button is inactive so we just slam it to off - other states don't matter - { - childSetEnabled( "current_url_reset_btn", false ); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable) -{ - LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; - self->mAutoLoop->clear(); - self->mAutoPlay->clear(); - self->mAutoScale->clear(); - self->mAutoZoom ->clear(); - self->mControls->clear(); - self->mCurrentURL->clear(); - self->mFirstClick->clear(); - self->mHeightPixels->clear(); - self->mHomeURL->clear(); - self->mWidthPixels->clear(); - self->mAutoLoop ->setEnabled(editable); - self->mAutoPlay ->setEnabled(editable); - self->mAutoScale ->setEnabled(editable); - self->mAutoZoom ->setEnabled(editable); - self->mControls ->setEnabled(editable); - self->mCurrentURL ->setEnabled(editable); - self->mFirstClick ->setEnabled(editable); - self->mHeightPixels ->setEnabled(editable); - self->mHomeURL ->setEnabled(editable); - self->mWidthPixels ->setEnabled(editable); - self->updateMediaPreview(); -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ,bool editable) -{ - LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; - self->mMediaEditable = editable; - - //llinfos << "---------------" << llendl; - //llinfos << ll_pretty_print_sd(media_settings) << llendl; - //llinfos << "---------------" << llendl; - - // IF all the faces have media (or all dont have media) - if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) - { - if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) - { - self->clearValues(self, self->mMediaEditable); - // only show multiple - self->mHomeURL ->setText(LLTrans::getString("Multiple Media")); - return; - } - - } - else - { - if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) - { - self->clearValues(self, self->mMediaEditable); - // only show multiple - self->mHomeURL ->setText(LLTrans::getString("Multiple Media")); - return; - } - - } - std::string base_key( "" ); - std::string tentative_key( "" ); - - struct - { - std::string key_name; - LLUICtrl* ctrl_ptr; - std::string ctrl_type; - - } data_set [] = - { - { LLMediaEntry::AUTO_LOOP_KEY, self->mAutoLoop, "LLCheckBoxCtrl" }, - { LLMediaEntry::AUTO_PLAY_KEY, self->mAutoPlay, "LLCheckBoxCtrl" }, - { LLMediaEntry::AUTO_SCALE_KEY, self->mAutoScale, "LLCheckBoxCtrl" }, - { LLMediaEntry::AUTO_ZOOM_KEY, self->mAutoZoom, "LLCheckBoxCtrl" }, - { LLMediaEntry::CONTROLS_KEY, self->mControls, "LLComboBox" }, - { LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLLineEditor" }, - { LLMediaEntry::HEIGHT_PIXELS_KEY, self->mHeightPixels, "LLSpinCtrl" }, - { LLMediaEntry::HOME_URL_KEY, self->mHomeURL, "LLLineEditor" }, - { LLMediaEntry::FIRST_CLICK_INTERACT_KEY, self->mFirstClick, "LLCheckBoxCtrl" }, - { LLMediaEntry::WIDTH_PIXELS_KEY, self->mWidthPixels, "LLSpinCtrl" }, - { "", NULL , "" } - }; - - for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) - { - base_key = std::string( data_set[ i ].key_name ); - tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); - // TODO: CP - I bet there is a better way to do this using Boost - if ( media_settings[ base_key ].isDefined() ) - { - if ( data_set[ i ].ctrl_type == "LLLineEditor" ) - { - static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )-> - setText( media_settings[ base_key ].asString() ); - } - else - if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) - static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> - setValue( media_settings[ base_key ].asBoolean() ); - else - if ( data_set[ i ].ctrl_type == "LLComboBox" ) - static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> - setCurrentByIndex( media_settings[ base_key ].asInteger() ); - else - if ( data_set[ i ].ctrl_type == "LLSpinCtrl" ) - static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )-> - setValue( media_settings[ base_key ].asInteger() ); - - data_set[ i ].ctrl_ptr->setEnabled(self->mMediaEditable); - data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); - }; - }; - - // interrogates controls and updates widgets as required - self->updateMediaPreview(); - self->updateCurrentURL(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Helper to set media control to media URL as required -void LLPanelMediaSettingsGeneral::updateMediaPreview() -{ - if ( mHomeURL->getValue().asString().length() > 0 ) - { - mPreviewMedia->navigateTo( mHomeURL->getValue().asString() ); - } - else - // new home URL will be empty if media is deleted so display a - // "preview goes here" data url page - { - mPreviewMedia->navigateTo( "data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%%22 height=%22100%%22 %3E%3Cdefs%3E%3Cpattern id=%22checker%22 patternUnits=%22userSpaceOnUse%22 x=%220%22 y=%220%22 width=%22128%22 height=%22128%22 viewBox=%220 0 128 128%22 %3E%3Crect x=%220%22 y=%220%22 width=%2264%22 height=%2264%22 fill=%22#ddddff%22 /%3E%3Crect x=%2264%22 y=%2264%22 width=%2264%22 height=%2264%22 fill=%22#ddddff%22 /%3E%3C/pattern%3E%3C/defs%3E%3Crect x=%220%22 y=%220%22 width=%22100%%22 height=%22100%%22 fill=%22url(#checker)%22 /%3E%3C/svg%3E" ); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// Helper to set current URL -void LLPanelMediaSettingsGeneral::updateCurrentURL() -{ - if( mCurrentURL->getText().empty() ) - { - childSetText( "current_url", mHomeURL->getText() ); - } - -} - -//////////////////////////////////////////////////////////////////////////////// - -// virtual -void LLPanelMediaSettingsGeneral::onClose(bool app_quitting) -{ - if(mPreviewMedia) - { - mPreviewMedia->unloadMediaSource(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata ) -{ - LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; - - // check url user is trying to enter for home URL will pass whitelist - // and decline to accept it if it doesn't. - std::string home_url = self->mHomeURL->getValue().asString(); - if ( ! self->mParent->passesWhiteList( home_url ) ) - { - LLNotifications::instance().add("WhiteListInvalidatesHomeUrl"); - return; - }; - - self->updateMediaPreview(); -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl(LLUICtrl* ctrl, void *userdata) -{ - LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; - self->navigateHomeSelectedFace(); -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsGeneral::apply( void* userdata ) -{ - LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; - self->mHomeURL->onCommit(); - // build LLSD Fragment - LLSD media_data_general; - self->getValues(media_data_general); - - // this merges contents of LLSD passed in with what's there so this is ok - LLSelectMgr::getInstance()->selectionSetMediaData( media_data_general ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in ) -{ - fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = mAutoLoop->getValue(); - fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = mAutoPlay->getValue(); - fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue(); - fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue(); - fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex(); - fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); - fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue(); - fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue(); - fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue(); - fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = mWidthPixels->getValue(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent ) -{ - mParent = parent; -}; - -bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace() -{ - // HACK: This is directly referencing an impl name. BAD! - // This can be removed when we have a truly generic media browser that only - // builds an impl based on the type of url it is passed. - struct functor_navigate_media : public LLSelectedTEGetFunctor< bool> - { - bool get( LLViewerObject* object, S32 face ) - { - if ( object ) - if ( object->getTE(face) ) - if ( object->getTE(face)->getMediaData() ) - { - if(object->permModify()) - { - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID()); - if(media_impl) - { - media_impl->navigateHome(); - return true; - } - } - } - return false; - }; - - } functor_navigate_media; - - bool all_face_media_navigated = false; - LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); - selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated ); - - return all_face_media_navigated; -} - -//////////////////////////////////////////////////////////////////////////////// -// -const std::string LLPanelMediaSettingsGeneral::getHomeUrl() -{ - return mHomeURL->getValue().asString(); -} - +/** + * @file llpanelmediasettingsgeneral.cpp + * @brief LLPanelMediaSettingsGeneral class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llpanelmediasettingsgeneral.h" +#include "llcombobox.h" +#include "llcheckboxctrl.h" +#include "llspinctrl.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" +#include "llviewermedia.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llbutton.h" +#include "lltexturectrl.h" +#include "llurl.h" +#include "llwindow.h" +#include "llmediaentry.h" +#include "llmediactrl.h" +#include "llpanelcontents.h" +#include "llpermissions.h" +#include "llpluginclassmedia.h" +#include "llfloatermediasettings.h" +#include "llfloatertools.h" +#include "lltrans.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() : + mControls( NULL ), + mAutoLoop( NULL ), + mFirstClick( NULL ), + mAutoZoom( NULL ), + mAutoPlay( NULL ), + mAutoScale( NULL ), + mWidthPixels( NULL ), + mHeightPixels( NULL ), + mHomeURL( NULL ), + mCurrentURL( NULL ), + mParent( NULL ), + mMediaEditable(false) +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_general.xml"); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsGeneral::postBuild() +{ + // connect member vars with UI widgets + mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY ); + mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY ); + mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY ); + mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY ); + mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY ); + mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY ); + mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); + mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY ); + mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY ); + mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY ); + mPreviewMedia = getChild<LLMediaCtrl>("preview_media"); + + // watch commit action for HOME URL + childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this); + childSetCommitCallback( "current_url_reset_btn",onBtnResetCurrentUrl, this); + // interrogates controls and updates widgets as required + updateMediaPreview(); + updateCurrentURL(); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::draw() +{ + // housekeeping + LLPanel::draw(); + + // enable/disable pixel values image entry based on auto scale checkbox + if ( mAutoScale->getValue().asBoolean() == false ) + { + childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, true ); + childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, true ); + } + else + { + childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, false ); + childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, false ); + }; + + // enable/disable UI based on type of media + bool reset_button_is_active = true; + if( mPreviewMedia ) + { + LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); + if( media_plugin ) + { + // turn off volume (if we can) for preview. Note: this really only + // works for QuickTime movies right now - no way to control the + // volume of a flash app embedded in a page for example + media_plugin->setVolume( 0 ); + + // some controls are only appropriate for time or browser type plugins + // so we selectively enable/disable them - need to do it in draw + // because the information from plugins arrives assynchronously + bool show_time_controls = media_plugin->pluginSupportsMediaTime(); + if ( show_time_controls ) + { + childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, false ); + reset_button_is_active = false; + childSetEnabled( "current_url_label", false ); + childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, true ); + } + else + { + childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, true ); + reset_button_is_active = true; + childSetEnabled( "current_url_label", true ); + childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, false ); + }; + }; + }; + + // current URL can change over time. +// updateCurrentURL(); + + LLPermissions perm; + bool user_can_press_reset = mMediaEditable; + + // several places modify this widget so we must collect states in one place + if ( reset_button_is_active ) + { + // user has perms to press reset button and it is active + if ( user_can_press_reset ) + { + childSetEnabled( "current_url_reset_btn", true ); + } + // user does not has perms to press reset button and it is active + else + { + childSetEnabled( "current_url_reset_btn", false ); + }; + } + else + // reset button is inactive so we just slam it to off - other states don't matter + { + childSetEnabled( "current_url_reset_btn", false ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + self->mAutoLoop->clear(); + self->mAutoPlay->clear(); + self->mAutoScale->clear(); + self->mAutoZoom ->clear(); + self->mControls->clear(); + self->mCurrentURL->clear(); + self->mFirstClick->clear(); + self->mHeightPixels->clear(); + self->mHomeURL->clear(); + self->mWidthPixels->clear(); + self->mAutoLoop ->setEnabled(editable); + self->mAutoPlay ->setEnabled(editable); + self->mAutoScale ->setEnabled(editable); + self->mAutoZoom ->setEnabled(editable); + self->mControls ->setEnabled(editable); + self->mCurrentURL ->setEnabled(editable); + self->mFirstClick ->setEnabled(editable); + self->mHeightPixels ->setEnabled(editable); + self->mHomeURL ->setEnabled(editable); + self->mWidthPixels ->setEnabled(editable); + self->updateMediaPreview(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ,bool editable) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + self->mMediaEditable = editable; + + //llinfos << "---------------" << llendl; + //llinfos << ll_pretty_print_sd(media_settings) << llendl; + //llinfos << "---------------" << llendl; + + // IF all the faces have media (or all dont have media) + if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) + { + if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) + { + self->clearValues(self, self->mMediaEditable); + // only show multiple + self->mHomeURL ->setText(LLTrans::getString("Multiple Media")); + return; + } + + } + else + { + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + self->clearValues(self, self->mMediaEditable); + // only show multiple + self->mHomeURL ->setText(LLTrans::getString("Multiple Media")); + return; + } + + } + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::AUTO_LOOP_KEY, self->mAutoLoop, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_PLAY_KEY, self->mAutoPlay, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_SCALE_KEY, self->mAutoScale, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_ZOOM_KEY, self->mAutoZoom, "LLCheckBoxCtrl" }, + { LLMediaEntry::CONTROLS_KEY, self->mControls, "LLComboBox" }, + { LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLLineEditor" }, + { LLMediaEntry::HEIGHT_PIXELS_KEY, self->mHeightPixels, "LLSpinCtrl" }, + { LLMediaEntry::HOME_URL_KEY, self->mHomeURL, "LLLineEditor" }, + { LLMediaEntry::FIRST_CLICK_INTERACT_KEY, self->mFirstClick, "LLCheckBoxCtrl" }, + { LLMediaEntry::WIDTH_PIXELS_KEY, self->mWidthPixels, "LLSpinCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLLineEditor" ) + { + static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )-> + setText( media_settings[ base_key ].asString() ); + } + else + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + else + if ( data_set[ i ].ctrl_type == "LLComboBox" ) + static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> + setCurrentByIndex( media_settings[ base_key ].asInteger() ); + else + if ( data_set[ i ].ctrl_type == "LLSpinCtrl" ) + static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asInteger() ); + + data_set[ i ].ctrl_ptr->setEnabled(self->mMediaEditable); + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; + + // interrogates controls and updates widgets as required + self->updateMediaPreview(); + self->updateCurrentURL(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper to set media control to media URL as required +void LLPanelMediaSettingsGeneral::updateMediaPreview() +{ + if ( mHomeURL->getValue().asString().length() > 0 ) + { + mPreviewMedia->navigateTo( mHomeURL->getValue().asString() ); + } + else + // new home URL will be empty if media is deleted so display a + // "preview goes here" data url page + { + mPreviewMedia->navigateTo( "data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%%22 height=%22100%%22 %3E%3Cdefs%3E%3Cpattern id=%22checker%22 patternUnits=%22userSpaceOnUse%22 x=%220%22 y=%220%22 width=%22128%22 height=%22128%22 viewBox=%220 0 128 128%22 %3E%3Crect x=%220%22 y=%220%22 width=%2264%22 height=%2264%22 fill=%22#ddddff%22 /%3E%3Crect x=%2264%22 y=%2264%22 width=%2264%22 height=%2264%22 fill=%22#ddddff%22 /%3E%3C/pattern%3E%3C/defs%3E%3Crect x=%220%22 y=%220%22 width=%22100%%22 height=%22100%%22 fill=%22url(#checker)%22 /%3E%3C/svg%3E" ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper to set current URL +void LLPanelMediaSettingsGeneral::updateCurrentURL() +{ + if( mCurrentURL->getText().empty() ) + { + childSetText( "current_url", mHomeURL->getText() ); + } + +} + +//////////////////////////////////////////////////////////////////////////////// + +// virtual +void LLPanelMediaSettingsGeneral::onClose(bool app_quitting) +{ + if(mPreviewMedia) + { + mPreviewMedia->unloadMediaSource(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata ) +{ + LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; + + // check url user is trying to enter for home URL will pass whitelist + // and decline to accept it if it doesn't. + std::string home_url = self->mHomeURL->getValue().asString(); + if ( ! self->mParent->passesWhiteList( home_url ) ) + { + LLNotifications::instance().add("WhiteListInvalidatesHomeUrl"); + return; + }; + + self->updateMediaPreview(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl(LLUICtrl* ctrl, void *userdata) +{ + LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; + self->navigateHomeSelectedFace(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::apply( void* userdata ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + self->mHomeURL->onCommit(); + // build LLSD Fragment + LLSD media_data_general; + self->getValues(media_data_general); + + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_general ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = mAutoLoop->getValue(); + fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = mAutoPlay->getValue(); + fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue(); + fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue(); + fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex(); + fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); + fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue(); + fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue(); + fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue(); + fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = mWidthPixels->getValue(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent ) +{ + mParent = parent; +}; + +bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace() +{ + // HACK: This is directly referencing an impl name. BAD! + // This can be removed when we have a truly generic media browser that only + // builds an impl based on the type of url it is passed. + struct functor_navigate_media : public LLSelectedTEGetFunctor< bool> + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + { + if(object->permModify()) + { + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID()); + if(media_impl) + { + media_impl->navigateHome(); + return true; + } + } + } + return false; + }; + + } functor_navigate_media; + + bool all_face_media_navigated = false; + LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); + selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated ); + + return all_face_media_navigated; +} + +//////////////////////////////////////////////////////////////////////////////// +// +const std::string LLPanelMediaSettingsGeneral::getHomeUrl() +{ + return mHomeURL->getValue().asString(); +} + diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp index f5607aa2874e03a6e21e62f84dfedfd907262792..3fe436e9157c0ccf26bd1571fa80924d07b476c5 100644 --- a/indra/newview/llpanelmediasettingssecurity.cpp +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -1,339 +1,339 @@ -/** - * @file llpanelmediasettingssecurity.cpp - * @brief LLPanelMediaSettingsSecurity class implementation - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llfloaterreg.h" -#include "llpanelmediasettingssecurity.h" -#include "llpanelcontents.h" -#include "llcheckboxctrl.h" -#include "llscrolllistctrl.h" -#include "llscrolllistitem.h" -#include "lluictrlfactory.h" -#include "llwindow.h" -#include "llviewerwindow.h" -#include "llsdutil.h" -#include "llselectmgr.h" -#include "llmediaentry.h" -#include "llfloaterwhitelistentry.h" -#include "llfloatermediasettings.h" -//////////////////////////////////////////////////////////////////////////////// -// -LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() : - mParent( NULL ) -{ - // build dialog from XML - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml"); - mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); - mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLPanelMediaSettingsSecurity::postBuild() -{ - mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY ); - mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY ); - - childSetAction("whitelist_add", onBtnAdd, this); - childSetAction("whitelist_del", onBtnDel, this); - - setDefaultBtn("whitelist_add"); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::draw() -{ - // housekeeping - LLPanel::draw(); - - // if list is empty, disable DEL button and checkbox to enable use of list - if ( mWhiteListList->isEmpty() ) - { - childSetEnabled( "whitelist_del", false ); - childSetEnabled( LLMediaEntry::WHITELIST_KEY, false ); - childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false ); - } - else - { - childSetEnabled( "whitelist_del", true ); - childSetEnabled( LLMediaEntry::WHITELIST_KEY, true ); - childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true ); - }; - - // if nothing is selected, disable DEL button - if ( mWhiteListList->getSelectedValue().asString().empty() ) - { - childSetEnabled( "whitelist_del", false ); - } - else - { - childSetEnabled( "whitelist_del", true ); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - - if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) - { - if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } - else - { - if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } - std::string base_key( "" ); - std::string tentative_key( "" ); - - struct - { - std::string key_name; - LLUICtrl* ctrl_ptr; - std::string ctrl_type; - - } data_set [] = - { - { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" }, - { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" }, - { "", NULL , "" } - }; - - for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) - { - base_key = std::string( data_set[ i ].key_name ); - tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); - - // TODO: CP - I bet there is a better way to do this using Boost - if ( media_settings[ base_key ].isDefined() ) - { - if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) - { - static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> - setValue( media_settings[ base_key ].asBoolean() ); - } - else - if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" ) - { - // get control - LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); - list->deleteAllItems(); - - // points to list of white list URLs - LLSD url_list = media_settings[ base_key ]; - - // iterate over them and add to scroll list - LLSD::array_iterator iter = url_list.beginArray(); - while( iter != url_list.endArray() ) - { - // TODO: is iter guaranteed to be valid here? - std::string url = *iter; - list->addSimpleElement( url ); - ++iter; - }; - }; - data_set[ i ].ctrl_ptr->setEnabled(editable); - data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); - }; - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - self->mEnableWhiteList->clear(); - self->mWhiteListList->deleteAllItems(); - self->mEnableWhiteList->setEnabled(editable); - self->mWhiteListList->setEnabled(editable); -} -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::apply( void* userdata ) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - - // build LLSD Fragment - LLSD media_data_security; - self->getValues(media_data_security); - // this merges contents of LLSD passed in with what's there so this is ok - LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) -{ - fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue(); - - // iterate over white list and extract items - std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); - std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); - fill_me_in[LLMediaEntry::WHITELIST_KEY].clear(); - while( iter != white_list_items.end() ) - { - std::string white_list_url = (*iter)->getValue().asString(); - fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url ); - ++iter; - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// Try to make a valid URL if a fragment ( -// white list list box widget and build a list to test against. Can also -const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& src_url ) -{ - // use LLURI to determine if we have a valid scheme +/** + * @file llpanelmediasettingssecurity.cpp + * @brief LLPanelMediaSettingsSecurity class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" +#include "llpanelmediasettingssecurity.h" +#include "llpanelcontents.h" +#include "llcheckboxctrl.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llfloaterwhitelistentry.h" +#include "llfloatermediasettings.h" +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() : + mParent( NULL ) +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml"); + mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); + mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsSecurity::postBuild() +{ + mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY ); + mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY ); + + childSetAction("whitelist_add", onBtnAdd, this); + childSetAction("whitelist_del", onBtnDel, this); + + setDefaultBtn("whitelist_add"); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::draw() +{ + // housekeeping + LLPanel::draw(); + + // if list is empty, disable DEL button and checkbox to enable use of list + if ( mWhiteListList->isEmpty() ) + { + childSetEnabled( "whitelist_del", false ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, false ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, true ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true ); + }; + + // if nothing is selected, disable DEL button + if ( mWhiteListList->getSelectedValue().asString().empty() ) + { + childSetEnabled( "whitelist_del", false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) + { + if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } + else + { + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" }, + { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + { + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + } + else + if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" ) + { + // get control + LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); + list->deleteAllItems(); + + // points to list of white list URLs + LLSD url_list = media_settings[ base_key ]; + + // iterate over them and add to scroll list + LLSD::array_iterator iter = url_list.beginArray(); + while( iter != url_list.endArray() ) + { + // TODO: is iter guaranteed to be valid here? + std::string url = *iter; + list->addSimpleElement( url ); + ++iter; + }; + }; + data_set[ i ].ctrl_ptr->setEnabled(editable); + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + self->mEnableWhiteList->clear(); + self->mWhiteListList->deleteAllItems(); + self->mEnableWhiteList->setEnabled(editable); + self->mWhiteListList->setEnabled(editable); +} +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::apply( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + // build LLSD Fragment + LLSD media_data_security; + self->getValues(media_data_security); + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue(); + + // iterate over white list and extract items + std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); + fill_me_in[LLMediaEntry::WHITELIST_KEY].clear(); + while( iter != white_list_items.end() ) + { + std::string white_list_url = (*iter)->getValue().asString(); + fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url ); + ++iter; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Try to make a valid URL if a fragment ( +// white list list box widget and build a list to test against. Can also +const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& src_url ) +{ + // use LLURI to determine if we have a valid scheme LLURI candidate_url( src_url ); if ( candidate_url.scheme().empty() ) { - // build a URL comprised of default scheme and the original fragment - const std::string default_scheme( "http://" ); - return default_scheme + src_url; + // build a URL comprised of default scheme and the original fragment + const std::string default_scheme( "http://" ); + return default_scheme + src_url; }; // we *could* test the "default scheme" + "original fragment" URL again // using LLURI to see if it's valid but I think the outcome is the same // in either case - our only option is to return the original URL - - // we *think* the original url passed in was valid - return src_url; -} - -/////////////////////////////////////////////////////////////////////////////// -// wrapper for testing a URL against the whitelist. We grab entries from -// white list list box widget and build a list to test against. Can also -// optionally pass the URL that you are trying to add to the widget since -// it won't be added until this call returns. -bool LLPanelMediaSettingsSecurity::passesWhiteList( const std::string& added_url, - const std::string& test_url ) -{ - // the checkUrlAgainstWhitelist(..) function works on a vector - // of strings for the white list entries - in this panel, the white list - // is stored in the widgets themselves so we need to build something compatible. - std::vector< std::string > whitelist_strings; - whitelist_strings.clear(); // may not be required - I forget what the spec says. - - // step through whitelist widget entries and grab them as strings - std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); - std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); - while( iter != white_list_items.end() ) - { - const std::string whitelist_url = (*iter)->getValue().asString(); - whitelist_strings.push_back( whitelist_url ); - - ++iter; - }; - - // add in the URL that might be added to the whitelist so we can test that too - if ( added_url.length() ) - whitelist_strings.push_back( added_url ); - - // possible the URL is just a fragment so we validize it - const std::string valid_url = makeValidUrl( test_url ); - - // indicate if the URL passes whitelist - return LLMediaEntry::checkUrlAgainstWhitelist( valid_url, whitelist_strings ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url) -{ - // grab home URL from the general panel (via the parent floater) - std::string home_url( "" ); - if ( mParent ) - home_url = mParent->getHomeUrl(); - - // if the home URL is blank (user hasn't entered it yet) then - // don't bother to check if it passes the white list - if ( home_url.empty() ) - { - mWhiteListList->addSimpleElement( url ); - return; - }; - - // if the URL passes the white list, add it - if ( passesWhiteList( url, home_url ) ) - { - mWhiteListList->addSimpleElement( url ); - } - else - // display a message indicating you can't do that - { - LLNotifications::instance().add("WhiteListInvalidatesHomeUrl"); - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata ) -{ - LLFloaterReg::showInstance("whitelist_entry"); -} - -/////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - - self->mWhiteListList->deleteSelectedItems(); -} - + + // we *think* the original url passed in was valid + return src_url; +} + +/////////////////////////////////////////////////////////////////////////////// +// wrapper for testing a URL against the whitelist. We grab entries from +// white list list box widget and build a list to test against. Can also +// optionally pass the URL that you are trying to add to the widget since +// it won't be added until this call returns. +bool LLPanelMediaSettingsSecurity::passesWhiteList( const std::string& added_url, + const std::string& test_url ) +{ + // the checkUrlAgainstWhitelist(..) function works on a vector + // of strings for the white list entries - in this panel, the white list + // is stored in the widgets themselves so we need to build something compatible. + std::vector< std::string > whitelist_strings; + whitelist_strings.clear(); // may not be required - I forget what the spec says. + + // step through whitelist widget entries and grab them as strings + std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); + while( iter != white_list_items.end() ) + { + const std::string whitelist_url = (*iter)->getValue().asString(); + whitelist_strings.push_back( whitelist_url ); + + ++iter; + }; + + // add in the URL that might be added to the whitelist so we can test that too + if ( added_url.length() ) + whitelist_strings.push_back( added_url ); + + // possible the URL is just a fragment so we validize it + const std::string valid_url = makeValidUrl( test_url ); + + // indicate if the URL passes whitelist + return LLMediaEntry::checkUrlAgainstWhitelist( valid_url, whitelist_strings ); +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url) +{ + // grab home URL from the general panel (via the parent floater) + std::string home_url( "" ); + if ( mParent ) + home_url = mParent->getHomeUrl(); + + // if the home URL is blank (user hasn't entered it yet) then + // don't bother to check if it passes the white list + if ( home_url.empty() ) + { + mWhiteListList->addSimpleElement( url ); + return; + }; + + // if the URL passes the white list, add it + if ( passesWhiteList( url, home_url ) ) + { + mWhiteListList->addSimpleElement( url ); + } + else + // display a message indicating you can't do that + { + LLNotifications::instance().add("WhiteListInvalidatesHomeUrl"); + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata ) +{ + LLFloaterReg::showInstance("whitelist_entry"); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + self->mWhiteListList->deleteSelectedItems(); +} + //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent ) diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h index b78ee921937e9829eb4ded4a7a62c1bda0be8ba4..2555bb8dc8546904ee646367d12a42c38d5fc389 100644 --- a/indra/newview/llpanelmediasettingssecurity.h +++ b/indra/newview/llpanelmediasettingssecurity.h @@ -55,7 +55,7 @@ class LLPanelMediaSettingsSecurity : public LLPanel void addWhiteListItem(const std::string& url); void setParent( LLFloaterMediaSettings* parent ); const std::string makeValidUrl( const std::string& src_url ); - bool passesWhiteList( const std::string& added_url, const std::string& test_url ); + bool passesWhiteList( const std::string& added_url, const std::string& test_url ); protected: LLFloaterMediaSettings* mParent; diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 365a6e632fac0e43407dd52f50b21e6a5a8f6df6..63fad7ddfdb8edcfa571bfb6eec005bdf6892d73 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1,1905 +1,1913 @@ -/** - * @file llsidepanelinventory.cpp - * @brief LLPanelObjectInventory class implementation - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -//***************************************************************************** -// -// Implementation of the panel inventory - used to view and control a -// task's inventory. -// -//***************************************************************************** - -#include "llviewerprecompiledheaders.h" - -#include "llpanelobjectinventory.h" - -#include "roles_constants.h" - -#include "llagent.h" -#include "llcallbacklist.h" -#include "llfloaterbuycurrency.h" -#include "llfloaterreg.h" -#include "llinventorybridge.h" -#include "llinventoryfunctions.h" -#include "llpreviewanim.h" -#include "llpreviewgesture.h" -#include "llpreviewnotecard.h" -#include "llpreviewscript.h" -#include "llpreviewsound.h" -#include "llpreviewtexture.h" -#include "llscrollcontainer.h" -#include "llselectmgr.h" -#include "llstatusbar.h" -#include "lltrans.h" -#include "llviewerregion.h" -#include "llviewerobjectlist.h" -#include "llviewermessage.h" - - -///---------------------------------------------------------------------------- -/// Class LLTaskInvFVBridge -///---------------------------------------------------------------------------- - -class LLTaskInvFVBridge : public LLFolderViewEventListener -{ -protected: - LLUUID mUUID; - std::string mName; - mutable std::string mDisplayName; - LLPanelObjectInventory* mPanel; - U32 mFlags; - - LLInventoryItem* findItem() const; - -public: - LLTaskInvFVBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name, - U32 flags=0); - virtual ~LLTaskInvFVBridge( void ) {} - - virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } - virtual std::string getLabelSuffix() const { return LLStringUtil::null; } - - static LLTaskInvFVBridge* createObjectBridge(LLPanelObjectInventory* panel, - LLInventoryObject* object); - void showProperties(); - void buyItem(); - S32 getPrice(); - static bool commitBuyItem(const LLSD& notification, const LLSD& response); - - // LLFolderViewEventListener functionality - virtual const std::string& getName() const; - virtual const std::string& getDisplayName() const; - virtual PermissionMask getPermissionMask() const { return PERM_NONE; } - /*virtual*/ LLAssetType::EType getPreferredType() const { return LLAssetType::AT_NONE; } - virtual const LLUUID& getUUID() const { return mUUID; } - virtual time_t getCreationDate() const; - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); - virtual void closeItem() {} - virtual void previewItem(); - virtual void selectItem() {} - virtual BOOL isItemRenameable() const; - virtual BOOL renameItem(const std::string& new_name); - virtual BOOL isItemMovable() const; - virtual BOOL isItemRemovable(); - virtual BOOL removeItem(); - virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch); - virtual void move(LLFolderViewEventListener* parent_listener); - virtual BOOL isItemCopyable() const; - virtual BOOL copyToClipboard() const; - virtual void cutToClipboard(); - virtual BOOL isClipboardPasteable() const; - virtual void pasteFromClipboard(); - virtual void pasteLinkFromClipboard(); - virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); - virtual BOOL isUpToDate() const { return TRUE; } - virtual BOOL hasChildren() const { return FALSE; } - virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } - // LLDragAndDropBridge functionality - virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; - virtual BOOL dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data); -}; - -LLTaskInvFVBridge::LLTaskInvFVBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name, - U32 flags): - mUUID(uuid), - mName(name), - mPanel(panel), - mFlags(flags) -{ - -} - -LLInventoryItem* LLTaskInvFVBridge::findItem() const -{ - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - return (LLInventoryItem*)(object->getInventoryObject(mUUID)); - } - return NULL; -} - -void LLTaskInvFVBridge::showProperties() -{ - LLFloaterProperties* floater = LLFloaterReg::showTypedInstance<LLFloaterProperties>("properties", mUUID); - if (floater) - { - floater->setObjectID(mPanel->getTaskUUID()); - } -} - -struct LLBuyInvItemData -{ - LLUUID mTaskID; - LLUUID mItemID; - LLAssetType::EType mType; - - LLBuyInvItemData(const LLUUID& task, - const LLUUID& item, - LLAssetType::EType type) : - mTaskID(task), mItemID(item), mType(type) - {} -}; - -void LLTaskInvFVBridge::buyItem() -{ - llinfos << "LLTaskInvFVBridge::buyItem()" << llendl; - LLInventoryItem* item = findItem(); - if(!item || !item->getSaleInfo().isForSale()) return; - LLBuyInvItemData* inv = new LLBuyInvItemData(mPanel->getTaskUUID(), - mUUID, - item->getType()); - - const LLSaleInfo& sale_info = item->getSaleInfo(); - const LLPermissions& perm = item->getPermissions(); - const std::string owner_name; // no owner name currently... FIXME? - - LLViewerObject* obj; - if( ( obj = gObjectList.findObject( mPanel->getTaskUUID() ) ) && obj->isAttachment() ) - { - LLNotifications::instance().add("Cannot_Purchase_an_Attachment"); - llinfos << "Attempt to purchase an attachment" << llendl; - delete inv; - } - else - { - LLSD args; - args["PRICE"] = llformat("%d",sale_info.getSalePrice()); - args["OWNER"] = owner_name; - if (sale_info.getSaleType() != LLSaleInfo::FS_CONTENTS) - { - U32 next_owner_mask = perm.getMaskNextOwner(); - args["MODIFYPERM"] = LLNotifications::instance().getGlobalString((next_owner_mask & PERM_MODIFY) ? "PermYes" : "PermNo"); - args["COPYPERM"] = LLNotifications::instance().getGlobalString((next_owner_mask & PERM_COPY) ? "PermYes" : "PermNo"); - args["RESELLPERM"] = LLNotifications::instance().getGlobalString((next_owner_mask & PERM_TRANSFER) ? "PermYes" : "PermNo"); - } - - std::string alertdesc; - switch(sale_info.getSaleType()) - { - case LLSaleInfo::FS_ORIGINAL: - alertdesc = owner_name.empty() ? "BuyOriginalNoOwner" : "BuyOriginal"; - break; - case LLSaleInfo::FS_CONTENTS: - alertdesc = owner_name.empty() ? "BuyContentsNoOwner" : "BuyContents"; - break; - case LLSaleInfo::FS_COPY: - default: - alertdesc = owner_name.empty() ? "BuyCopyNoOwner" : "BuyCopy"; - break; - } - - LLSD payload; - payload["task_id"] = inv->mTaskID; - payload["item_id"] = inv->mItemID; - payload["type"] = inv->mType; - LLNotifications::instance().add(alertdesc, args, payload, LLTaskInvFVBridge::commitBuyItem); - } -} - -S32 LLTaskInvFVBridge::getPrice() -{ - LLInventoryItem* item = findItem(); - if(item) - { - return item->getSaleInfo().getSalePrice(); - } - else - { - return -1; - } -} - -// static -bool LLTaskInvFVBridge::commitBuyItem(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if(0 == option) - { - LLViewerObject* object = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); - if(!object || !object->getRegion()) return false; - - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_BuyObjectInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_ObjectID, notification["payload"]["task_id"].asUUID()); - msg->addUUIDFast(_PREHASH_ItemID, notification["payload"]["item_id"].asUUID()); - msg->addUUIDFast(_PREHASH_FolderID, - gInventory.findCategoryUUIDForType((LLAssetType::EType)notification["payload"]["type"].asInteger())); - msg->sendReliable(object->getRegion()->getHost()); - } - return false; -} - -const std::string& LLTaskInvFVBridge::getName() const -{ - return mName; -} - -const std::string& LLTaskInvFVBridge::getDisplayName() const -{ - LLInventoryItem* item = findItem(); - if(item) - { - mDisplayName.assign(item->getName()); - - const LLPermissions& perm(item->getPermissions()); - BOOL copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE); - BOOL mod = gAgent.allowOperation(PERM_MODIFY, perm, GP_OBJECT_MANIPULATE); - BOOL xfer = gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE); - - if(!copy) - { - mDisplayName.append(" (no copy)"); - } - if(!mod) - { - mDisplayName.append(" (no modify)"); - } - if(!xfer) - { - mDisplayName.append(" (no transfer)"); - } - } - - return mDisplayName; -} - -// BUG: No creation dates for task inventory -time_t LLTaskInvFVBridge::getCreationDate() const -{ - return 0; -} - -LLUIImagePtr LLTaskInvFVBridge::getIcon() const -{ - BOOL item_is_multi = FALSE; - if ( mFlags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) - { - item_is_multi = TRUE; - } - - return get_item_icon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi ); -} - -void LLTaskInvFVBridge::openItem() -{ - // no-op. - lldebugs << "LLTaskInvFVBridge::openItem()" << llendl; -} - -void LLTaskInvFVBridge::previewItem() -{ - openItem(); -} - -BOOL LLTaskInvFVBridge::isItemRenameable() const -{ - if(gAgent.isGodlike()) return TRUE; - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - LLInventoryItem* item; - item = (LLInventoryItem*)(object->getInventoryObject(mUUID)); - if(item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), - GP_OBJECT_MANIPULATE, GOD_LIKE)) - { - return TRUE; - } - } - return FALSE; -} - -BOOL LLTaskInvFVBridge::renameItem(const std::string& new_name) -{ - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)object->getInventoryObject(mUUID); - if(item && (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), - GP_OBJECT_MANIPULATE, GOD_LIKE))) - { - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - object->updateInventory( - new_item, - TASK_INVENTORY_ITEM_KEY, - false); - } - } - return TRUE; -} - -BOOL LLTaskInvFVBridge::isItemMovable() const -{ - //LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - //if(object && (object->permModify() || gAgent.isGodlike())) - //{ - // return TRUE; - //} - //return FALSE; - return TRUE; -} - -BOOL LLTaskInvFVBridge::isItemRemovable() -{ - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object - && (object->permModify() || object->permYouOwner())) - { - return TRUE; - } - return FALSE; -} - -bool remove_task_inventory_callback(const LLSD& notification, const LLSD& response, LLPanelObjectInventory* panel) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLViewerObject* object = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); - if(option == 0 && object) - { - // yes - LLSD::array_const_iterator list_end = notification["payload"]["inventory_ids"].endArray(); - for (LLSD::array_const_iterator list_it = notification["payload"]["inventory_ids"].beginArray(); - list_it != list_end; - ++list_it) - { - object->removeInventory(list_it->asUUID()); - } - - // refresh the UI. - panel->refresh(); - } - return false; -} - -// helper for remove -// ! REFACTOR ! two_uuids_list_t is also defined in llinevntorybridge.h, but differently. -typedef std::pair<LLUUID, std::list<LLUUID> > panel_two_uuids_list_t; -typedef std::pair<LLPanelObjectInventory*, panel_two_uuids_list_t> remove_data_t; -BOOL LLTaskInvFVBridge::removeItem() -{ - if(isItemRemovable() && mPanel) - { - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - if(object->permModify()) - { - // just do it. - object->removeInventory(mUUID); - return TRUE; - } - else - { - remove_data_t* data = new remove_data_t; - data->first = mPanel; - data->second.first = mPanel->getTaskUUID(); - data->second.second.push_back(mUUID); - LLSD payload; - payload["task_id"] = mPanel->getTaskUUID(); - payload["inventory_ids"].append(mUUID); - LLNotifications::instance().add("RemoveItemWarn", LLSD(), payload, boost::bind(&remove_task_inventory_callback, _1, _2, mPanel)); - return FALSE; - } - } - } - return FALSE; -} - -void LLTaskInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) -{ - if (!mPanel) - { - return; - } - - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if (!object) - { - return; - } - - if (!object->permModify()) - { - LLSD payload; - payload["task_id"] = mPanel->getTaskUUID(); - for (S32 i = 0; i < (S32)batch.size(); i++) - { - LLTaskInvFVBridge* itemp = (LLTaskInvFVBridge*)batch[i]; - payload["inventory_ids"].append(itemp->getUUID()); - } - LLNotifications::instance().add("RemoveItemWarn", LLSD(), payload, boost::bind(&remove_task_inventory_callback, _1, _2, mPanel)); - - } - else - { - for (S32 i = 0; i < (S32)batch.size(); i++) - { - LLTaskInvFVBridge* itemp = (LLTaskInvFVBridge*)batch[i]; - - if(itemp->isItemRemovable()) - { - // just do it. - object->removeInventory(itemp->getUUID()); - } - } - } -} - -void LLTaskInvFVBridge::move(LLFolderViewEventListener* parent_listener) -{ -} - -BOOL LLTaskInvFVBridge::isItemCopyable() const -{ - LLInventoryItem* item = findItem(); - if(!item) return FALSE; - return gAgent.allowOperation(PERM_COPY, item->getPermissions(), - GP_OBJECT_MANIPULATE); -} - -BOOL LLTaskInvFVBridge::copyToClipboard() const -{ - return FALSE; -} - -void LLTaskInvFVBridge::cutToClipboard() -{ -} - -BOOL LLTaskInvFVBridge::isClipboardPasteable() const -{ - return FALSE; -} - -void LLTaskInvFVBridge::pasteFromClipboard() -{ -} - -void LLTaskInvFVBridge::pasteLinkFromClipboard() -{ -} - -BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const -{ - //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; - if(mPanel) - { - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - LLInventoryItem* inv = NULL; - if((inv = (LLInventoryItem*)object->getInventoryObject(mUUID))) - { - const LLPermissions& perm = inv->getPermissions(); - bool can_copy = gAgent.allowOperation(PERM_COPY, perm, - GP_OBJECT_MANIPULATE); - if (object->isAttachment() && !can_copy) - { - //RN: no copy contents of attachments cannot be dragged out - // due to a race condition and possible exploit where - // attached objects do not update their inventory items - // when their contents are manipulated - return FALSE; - } - if((can_copy && perm.allowTransferTo(gAgent.getID())) - || object->permYouOwner()) -// || gAgent.isGodlike()) - - { - *type = LLAssetType::lookupDragAndDropType(inv->getType()); - - *id = inv->getUUID(); - return TRUE; - } - } - } - } - return FALSE; -} - -BOOL LLTaskInvFVBridge::dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data) -{ - //llinfos << "LLTaskInvFVBridge::dragOrDrop()" << llendl; - return FALSE; -} - -// virtual -void LLTaskInvFVBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if (action == "task_buy") - { - // Check the price of the item. - S32 price = getPrice(); - if (-1 == price) - { - llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; - } - else - { - if (price > 0 && price > gStatusBar->getBalance()) - { - LLFloaterBuyCurrency::buyCurrency("This costs", price); - } - else - { - buyItem(); - } - } - } - else if (action == "task_open") - { - openItem(); - } - else if (action == "task_properties") - { - showProperties(); - } -} - -void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LLInventoryItem* item = findItem(); - std::vector<std::string> items; - std::vector<std::string> disabled_items; - - if (!item) - { - hide_context_entries(menu, items, disabled_items); - return; - } - - if(gAgent.allowOperation(PERM_OWNER, item->getPermissions(), - GP_OBJECT_MANIPULATE) - && item->getSaleInfo().isForSale()) - { - items.push_back(std::string("Task Buy")); - - std::string label= LLTrans::getString("Buy"); - // Check the price of the item. - S32 price = getPrice(); - if (-1 == price) - { - llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; - } - else - { - std::ostringstream info; - info << LLTrans::getString("BuyforL$") << price; - label.assign(info.str()); - } - - const LLView::child_list_t *list = menu.getChildList(); - LLView::child_list_t::const_iterator itor; - for (itor = list->begin(); itor != list->end(); ++itor) - { - std::string name = (*itor)->getName(); - LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor); - if (name == "Task Buy" && menu_itemp) - { - menu_itemp->setLabel(label); - } - } - } - else - { - items.push_back(std::string("Task Open")); - if (!isItemCopyable()) - { - disabled_items.push_back(std::string("Task Open")); - } - } - items.push_back(std::string("Task Properties")); - if(isItemRenameable()) - { - items.push_back(std::string("Task Rename")); - } - if(isItemRemovable()) - { - items.push_back(std::string("Task Remove")); - } - - hide_context_entries(menu, items, disabled_items); -} - - -///---------------------------------------------------------------------------- -/// Class LLTaskFolderBridge -///---------------------------------------------------------------------------- - -class LLTaskCategoryBridge : public LLTaskInvFVBridge -{ -public: - LLTaskCategoryBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - virtual const std::string& getDisplayName() const { return getName(); } - virtual BOOL isItemRenameable() const; - virtual BOOL renameItem(const std::string& new_name); - virtual BOOL isItemRemovable(); - virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual BOOL hasChildren() const; - virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; - virtual BOOL dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data); -}; - -LLTaskCategoryBridge::LLTaskCategoryBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskCategoryBridge::getIcon() const -{ - return LLUI::getUIImage("Inv_FolderClosed"); -} - -BOOL LLTaskCategoryBridge::isItemRenameable() const -{ - return FALSE; -} - -BOOL LLTaskCategoryBridge::renameItem(const std::string& new_name) -{ - return FALSE; -} - -BOOL LLTaskCategoryBridge::isItemRemovable() -{ - return FALSE; -} - -void LLTaskCategoryBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - std::vector<std::string> items; - std::vector<std::string> disabled_items; - items.push_back(std::string("Task Open")); - hide_context_entries(menu, items, disabled_items); -} - -BOOL LLTaskCategoryBridge::hasChildren() const -{ - // return TRUE if we have or do know know if we have children. - // *FIX: For now, return FALSE - we will know for sure soon enough. - return FALSE; -} - -BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const -{ - //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; - if(mPanel) - { - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - LLInventoryItem* inv = NULL; - if((inv = (LLInventoryItem*)object->getInventoryObject(mUUID))) - { - const LLPermissions& perm = inv->getPermissions(); - bool can_copy = gAgent.allowOperation(PERM_COPY, perm, - GP_OBJECT_MANIPULATE); - if((can_copy && perm.allowTransferTo(gAgent.getID())) - || object->permYouOwner()) -// || gAgent.isGodlike()) - - { - *type = LLAssetType::lookupDragAndDropType(inv->getType()); - - *id = inv->getUUID(); - return TRUE; - } - } - } - } - return FALSE; -} - -BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data) -{ - //llinfos << "LLTaskCategoryBridge::dragOrDrop()" << llendl; - BOOL accept = FALSE; - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(object) - { - switch(cargo_type) - { - case DAD_CATEGORY: - accept = LLToolDragAndDrop::getInstance()->dadUpdateInventoryCategory(object,drop); - break; - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_LANDMARK: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_CLOTHING: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - case DAD_CALLINGCARD: - accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); - if(accept && drop) - { - LLToolDragAndDrop::dropInventory(object, - (LLViewerInventoryItem*)cargo_data, - LLToolDragAndDrop::getInstance()->getSource(), - LLToolDragAndDrop::getInstance()->getSourceID()); - } - break; - case DAD_SCRIPT: - // *HACK: In order to resolve SL-22177, we need to block - // drags from notecards and objects onto other - // objects. uncomment the simpler version when we have - // that right. - //accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); - if(LLToolDragAndDrop::isInventoryDropAcceptable( - object, (LLViewerInventoryItem*)cargo_data) - && (LLToolDragAndDrop::SOURCE_WORLD != LLToolDragAndDrop::getInstance()->getSource()) - && (LLToolDragAndDrop::SOURCE_NOTECARD != LLToolDragAndDrop::getInstance()->getSource())) - { - accept = TRUE; - } - if(accept && drop) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)cargo_data; - // rez in the script active by default, rez in - // inactive if the control key is being held down. - BOOL active = ((mask & MASK_CONTROL) == 0); - LLToolDragAndDrop::dropScript(object, item, active, - LLToolDragAndDrop::getInstance()->getSource(), - LLToolDragAndDrop::getInstance()->getSourceID()); - } - break; - default: - break; - } - } - return accept; -} - -///---------------------------------------------------------------------------- -/// Class LLTaskTextureBridge -///---------------------------------------------------------------------------- - -class LLTaskTextureBridge : public LLTaskInvFVBridge -{ -public: - LLTaskTextureBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLInventoryType::EType it); - - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); -protected: - LLInventoryType::EType mInventoryType; -}; - -LLTaskTextureBridge::LLTaskTextureBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLInventoryType::EType it) : - LLTaskInvFVBridge(panel, uuid, name), - mInventoryType(it) -{ -} - -LLUIImagePtr LLTaskTextureBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_TEXTURE, mInventoryType, 0, FALSE); -} - -void LLTaskTextureBridge::openItem() -{ - llinfos << "LLTaskTextureBridge::openItem()" << llendl; - LLPreviewTexture* preview = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); - if(preview) - { - preview->setObjectID(mPanel->getTaskUUID()); - } -} - - -///---------------------------------------------------------------------------- -/// Class LLTaskSoundBridge -///---------------------------------------------------------------------------- - -class LLTaskSoundBridge : public LLTaskInvFVBridge -{ -public: - LLTaskSoundBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); - virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - static void openSoundPreview(void* data); -}; - -LLTaskSoundBridge::LLTaskSoundBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskSoundBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); -} - -void LLTaskSoundBridge::openItem() -{ - openSoundPreview((void*)this); -} - -void LLTaskSoundBridge::openSoundPreview(void* data) -{ - LLTaskSoundBridge* self = (LLTaskSoundBridge*)data; - if(!self) - return; - - LLPreviewSound* preview = LLFloaterReg::showTypedInstance<LLPreviewSound>("preview_sound", LLSD(self->mUUID), TAKE_FOCUS_YES); - if (preview) - { - preview->setObjectID(self->mPanel->getTaskUUID()); - } -} - -// virtual -void LLTaskSoundBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if (action == "task_play") - { - LLInventoryItem* item = findItem(); - if(item) - { - send_sound_trigger(item->getAssetUUID(), 1.0); - } - } - LLTaskInvFVBridge::performAction(folder, model, action); -} - -void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LLInventoryItem* item = findItem(); - if(!item) return; - std::vector<std::string> items; - std::vector<std::string> disabled_items; - - if(item->getPermissions().getOwner() != gAgent.getID() - && item->getSaleInfo().isForSale()) - { - items.push_back(std::string("Task Buy")); - - std::string label= LLTrans::getString("Buy"); - // Check the price of the item. - S32 price = getPrice(); - if (-1 == price) - { - llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; - } - else - { - std::ostringstream info; - info << LLTrans::getString("BuyforL$") << price; - label.assign(info.str()); - } - - const LLView::child_list_t *list = menu.getChildList(); - LLView::child_list_t::const_iterator itor; - for (itor = list->begin(); itor != list->end(); ++itor) - { - std::string name = (*itor)->getName(); - LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor); - if (name == "Task Buy" && menu_itemp) - { - menu_itemp->setLabel(label); - } - } - } - else - { - items.push_back(std::string("Task Open")); - if (!isItemCopyable()) - { - disabled_items.push_back(std::string("Task Open")); - } - } - items.push_back(std::string("Task Properties")); - if(isItemRenameable()) - { - items.push_back(std::string("Task Rename")); - } - if(isItemRemovable()) - { - items.push_back(std::string("Task Remove")); - } - - items.push_back(std::string("Task Play")); - - - hide_context_entries(menu, items, disabled_items); -} - -///---------------------------------------------------------------------------- -/// Class LLTaskLandmarkBridge -///---------------------------------------------------------------------------- - -class LLTaskLandmarkBridge : public LLTaskInvFVBridge -{ -public: - LLTaskLandmarkBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; -}; - -LLTaskLandmarkBridge::LLTaskLandmarkBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskLandmarkBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, 0, FALSE); -} - - -///---------------------------------------------------------------------------- -/// Class LLTaskCallingCardBridge -///---------------------------------------------------------------------------- - -class LLTaskCallingCardBridge : public LLTaskInvFVBridge -{ -public: - LLTaskCallingCardBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - virtual BOOL isItemRenameable() const; - virtual BOOL renameItem(const std::string& new_name); -}; - -LLTaskCallingCardBridge::LLTaskCallingCardBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskCallingCardBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, 0, FALSE); -} - -BOOL LLTaskCallingCardBridge::isItemRenameable() const -{ - return FALSE; -} - -BOOL LLTaskCallingCardBridge::renameItem(const std::string& new_name) -{ - return FALSE; -} - - -///---------------------------------------------------------------------------- -/// Class LLTaskScriptBridge -///---------------------------------------------------------------------------- - -class LLTaskScriptBridge : public LLTaskInvFVBridge -{ -public: - LLTaskScriptBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - //static BOOL enableIfCopyable( void* userdata ); -}; - -LLTaskScriptBridge::LLTaskScriptBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskScriptBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); -} - - -class LLTaskLSLBridge : public LLTaskScriptBridge -{ -public: - LLTaskLSLBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual void openItem(); - virtual BOOL removeItem(); - //virtual void buildContextMenu(LLMenuGL& menu); - - //static void copyToInventory(void* userdata); -}; - -LLTaskLSLBridge::LLTaskLSLBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskScriptBridge(panel, uuid, name) -{ -} - -void LLTaskLSLBridge::openItem() -{ - llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(!object || object->isInventoryPending()) - { - return; - } - LLLiveLSLEditor* preview = LLFloaterReg::showTypedInstance<LLLiveLSLEditor>("preview_scriptedit", LLSD(mUUID), TAKE_FOCUS_YES); - if (preview && (object->permModify() || gAgent.isGodlike())) - { - preview->setObjectID(mPanel->getTaskUUID()); - } -} - -BOOL LLTaskLSLBridge::removeItem() -{ - LLFloaterReg::hideInstance("preview_scriptedit", LLSD(mUUID)); - return LLTaskInvFVBridge::removeItem(); -} - -///---------------------------------------------------------------------------- -/// Class LLTaskObjectBridge -///---------------------------------------------------------------------------- - -class LLTaskObjectBridge : public LLTaskInvFVBridge -{ -public: - LLTaskObjectBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; -}; - -LLTaskObjectBridge::LLTaskObjectBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskObjectBridge::getIcon() const -{ - BOOL item_is_multi = FALSE; - if ( mFlags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) - { - item_is_multi = TRUE; - } - - return get_item_icon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi); -} - -///---------------------------------------------------------------------------- -/// Class LLTaskNotecardBridge -///---------------------------------------------------------------------------- - -class LLTaskNotecardBridge : public LLTaskInvFVBridge -{ -public: - LLTaskNotecardBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); - virtual BOOL removeItem(); -}; - -LLTaskNotecardBridge::LLTaskNotecardBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskNotecardBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); -} - -void LLTaskNotecardBridge::openItem() -{ - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(!object || object->isInventoryPending()) - { - return; - } - if(object->permModify() || gAgent.isGodlike()) - { - LLPreviewNotecard* preview = LLFloaterReg::showTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(mUUID), TAKE_FOCUS_YES); - if (preview) - { - preview->setObjectID(mPanel->getTaskUUID()); - } - } -} - -BOOL LLTaskNotecardBridge::removeItem() -{ - LLFloaterReg::hideInstance("preview_notecard", LLSD(mUUID)); - return LLTaskInvFVBridge::removeItem(); -} - -///---------------------------------------------------------------------------- -/// Class LLTaskGestureBridge -///---------------------------------------------------------------------------- - -class LLTaskGestureBridge : public LLTaskInvFVBridge -{ -public: - LLTaskGestureBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); - virtual BOOL removeItem(); -}; - -LLTaskGestureBridge::LLTaskGestureBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskGestureBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); -} - -void LLTaskGestureBridge::openItem() -{ - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(!object || object->isInventoryPending()) - { - return; - } - LLPreviewGesture::show(mUUID, mPanel->getTaskUUID()); -} - -BOOL LLTaskGestureBridge::removeItem() -{ - // Don't need to deactivate gesture because gestures inside objects can never be active. - LLFloaterReg::hideInstance("preview_gesture", LLSD(mUUID)); - return LLTaskInvFVBridge::removeItem(); -} - -///---------------------------------------------------------------------------- -/// Class LLTaskAnimationBridge -///---------------------------------------------------------------------------- - -class LLTaskAnimationBridge : public LLTaskInvFVBridge -{ -public: - LLTaskAnimationBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name); - - virtual LLUIImagePtr getIcon() const; - virtual void openItem(); - virtual BOOL removeItem(); -}; - -LLTaskAnimationBridge::LLTaskAnimationBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name) : - LLTaskInvFVBridge(panel, uuid, name) -{ -} - -LLUIImagePtr LLTaskAnimationBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); -} - -void LLTaskAnimationBridge::openItem() -{ - LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if(!object || object->isInventoryPending()) - { - return; - } - - LLPreviewAnim* preview = LLFloaterReg::showTypedInstance<LLPreviewAnim>("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); - if (preview && (object->permModify() || gAgent.isGodlike())) - { - preview->setObjectID(mPanel->getTaskUUID()); - } -} - -BOOL LLTaskAnimationBridge::removeItem() -{ - LLFloaterReg::hideInstance("preview_anim", LLSD(mUUID)); - return LLTaskInvFVBridge::removeItem(); -} - -///---------------------------------------------------------------------------- -/// Class LLTaskWearableBridge -///---------------------------------------------------------------------------- - -class LLTaskWearableBridge : public LLTaskInvFVBridge -{ -public: - LLTaskWearableBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLAssetType::EType asset_type, - U32 flags); - - virtual LLUIImagePtr getIcon() const; - -protected: - LLAssetType::EType mAssetType; -}; - -LLTaskWearableBridge::LLTaskWearableBridge( - LLPanelObjectInventory* panel, - const LLUUID& uuid, - const std::string& name, - LLAssetType::EType asset_type, - U32 flags) : - LLTaskInvFVBridge(panel, uuid, name, flags), - mAssetType( asset_type ) -{ -} - -LLUIImagePtr LLTaskWearableBridge::getIcon() const -{ - return get_item_icon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE ); -} - - -///---------------------------------------------------------------------------- -/// LLTaskInvFVBridge impl -//---------------------------------------------------------------------------- - -LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* panel, - LLInventoryObject* object) -{ - LLTaskInvFVBridge* new_bridge = NULL; - LLAssetType::EType type = object->getType(); - LLInventoryItem* item = NULL; - switch(type) - { - case LLAssetType::AT_TEXTURE: - item = (LLInventoryItem*)object; - new_bridge = new LLTaskTextureBridge(panel, - object->getUUID(), - object->getName(), - item->getInventoryType()); - break; - case LLAssetType::AT_SOUND: - new_bridge = new LLTaskSoundBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_LANDMARK: - new_bridge = new LLTaskLandmarkBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_CALLINGCARD: - new_bridge = new LLTaskCallingCardBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_SCRIPT: - // OLD SCRIPTS DEPRECATED - JC - llwarns << "Old script" << llendl; - //new_bridge = new LLTaskOldScriptBridge(panel, - // object->getUUID(), - // object->getName()); - break; - case LLAssetType::AT_OBJECT: - new_bridge = new LLTaskObjectBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_NOTECARD: - new_bridge = new LLTaskNotecardBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_ANIMATION: - new_bridge = new LLTaskAnimationBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_GESTURE: - new_bridge = new LLTaskGestureBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - item = (LLInventoryItem*)object; - new_bridge = new LLTaskWearableBridge(panel, - object->getUUID(), - object->getName(), - type, - item->getFlags()); - break; - case LLAssetType::AT_CATEGORY: - case LLAssetType::AT_FAVORITE: - new_bridge = new LLTaskCategoryBridge(panel, - object->getUUID(), - object->getName()); - break; - case LLAssetType::AT_LSL_TEXT: - new_bridge = new LLTaskLSLBridge(panel, - object->getUUID(), - object->getName()); - break; - - break; - default: - llinfos << "Unhandled inventory type (llassetstorage.h): " - << (S32)type << llendl; - break; - } - return new_bridge; -} - - -///---------------------------------------------------------------------------- -/// Class LLPanelObjectInventory -///---------------------------------------------------------------------------- - -static LLDefaultChildRegistry::Register<LLPanelObjectInventory> r("panel_inventory_object"); - -void do_nothing() -{ -} - -// Default constructor -LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Params& p) : - LLPanel(p), - mScroller(NULL), - mFolders(NULL), - mHaveInventory(FALSE), - mIsInventoryEmpty(TRUE), - mInventoryNeedsUpdate(FALSE) -{ - // Setup context menu callbacks - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&do_nothing)); - mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&do_nothing)); - mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&do_nothing)); -} - -// Destroys the object -LLPanelObjectInventory::~LLPanelObjectInventory() -{ - if (!gIdleCallbacks.deleteFunction(idle, this)) - { - llwarns << "LLPanelObjectInventory::~LLPanelObjectInventory() failed to delete callback" << llendl; - } -} - -BOOL LLPanelObjectInventory::postBuild() -{ - // clear contents and initialize menus, sets up mFolders - reset(); - - // Register an idle update callback - gIdleCallbacks.addFunction(idle, this); - - return TRUE; -} - -void LLPanelObjectInventory::doToSelected(const LLSD& userdata) -{ - mFolders->doToSelected(&gInventory, userdata); -} - -void LLPanelObjectInventory::clearContents() -{ - mHaveInventory = FALSE; - mIsInventoryEmpty = TRUE; - if (LLToolDragAndDrop::getInstance() && LLToolDragAndDrop::getInstance()->getSource() == LLToolDragAndDrop::SOURCE_WORLD) - { - LLToolDragAndDrop::getInstance()->endDrag(); - } - - if( mScroller ) - { - // removes mFolders - removeChild( mScroller ); //*TODO: Really shouldn't do this during draw()/refresh() - mScroller->die(); - mScroller = NULL; - mFolders = NULL; - } -} - - -void LLPanelObjectInventory::reset() -{ - clearContents(); - - setBorderVisible(FALSE); - - mCommitCallbackRegistrar.pushScope(); // push local callbacks - - LLRect dummy_rect(0, 1, 1, 0); - LLFolderView::Params p; - p.name = "task inventory"; - p.task_id = getTaskUUID(); - p.parent_panel = this; - mFolders = LLUICtrlFactory::create<LLFolderView>(p); - // this ensures that we never say "searching..." or "no items found" - mFolders->getFilter()->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); - mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); - - LLRect scroller_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - LLScrollContainer::Params scroll_p; - scroll_p.name("task inventory scroller"); - scroll_p.rect(scroller_rect); - scroll_p.follows.flags(FOLLOWS_ALL); - mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_p); - addChild(mScroller); - mScroller->addChild(mFolders); - - mFolders->setScrollContainer( mScroller ); - - mCommitCallbackRegistrar.popScope(); -} - -void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, - InventoryObjectList* inventory, - S32 serial_num, - void* data) -{ - if(!object) return; - - //llinfos << "invetnory arrived: \n" - // << " panel UUID: " << panel->mTaskUUID << "\n" - // << " task UUID: " << object->mID << llendl; - if(mTaskUUID == object->mID) - { - mInventoryNeedsUpdate = TRUE; - } - - // refresh any properties floaters that are hanging around. - if(inventory) - { - for (InventoryObjectList::const_iterator iter = inventory->begin(); - iter != inventory->end(); ) - { - LLInventoryObject* item = *iter++; - LLFloaterProperties* floater = LLFloaterReg::findTypedInstance<LLFloaterProperties>("properites", item->getUUID()); - if(floater) - { - floater->refresh(); - } - } - } -} - -void LLPanelObjectInventory::updateInventory() -{ - //llinfos << "inventory arrived: \n" - // << " panel UUID: " << panel->mTaskUUID << "\n" - // << " task UUID: " << object->mID << llendl; - // We're still interested in this task's inventory. - std::set<LLUUID> selected_items; - BOOL inventory_has_focus = FALSE; - if (mHaveInventory && mFolders->getNumSelectedDescendants()) - { - mFolders->getSelectionList(selected_items); - inventory_has_focus = gFocusMgr.childHasKeyboardFocus(mFolders); - } - - reset(); - - LLViewerObject* objectp = gObjectList.findObject(mTaskUUID); - if (objectp) - { - LLInventoryObject* inventory_root = objectp->getInventoryRoot(); - InventoryObjectList contents; - objectp->getInventoryContents(contents); - if (inventory_root) - { - createFolderViews(inventory_root, contents); - mHaveInventory = TRUE; - mIsInventoryEmpty = FALSE; - mFolders->setEnabled(TRUE); - } - else - { - // TODO: create an empty inventory - mIsInventoryEmpty = TRUE; - mHaveInventory = TRUE; - } - } - else - { - // TODO: create an empty inventory - mIsInventoryEmpty = TRUE; - mHaveInventory = TRUE; - } - - // restore previous selection - std::set<LLUUID>::iterator selection_it; - BOOL first_item = TRUE; - for (selection_it = selected_items.begin(); selection_it != selected_items.end(); ++selection_it) - { - LLFolderViewItem* selected_item = mFolders->getItemByID(*selection_it); - if (selected_item) - { - //HACK: "set" first item then "change" each other one to get keyboard focus right - if (first_item) - { - mFolders->setSelection(selected_item, TRUE, inventory_has_focus); - first_item = FALSE; - } - else - { - mFolders->changeSelection(selected_item, TRUE); - } - } - } - - mFolders->requestArrange(); - mInventoryNeedsUpdate = FALSE; -} - -// *FIX: This is currently a very expensive operation, because we have -// to iterate through the inventory one time for each category. This -// leads to an N^2 based on the category count. This could be greatly -// speeded with an efficient multimap implementation, but we don't -// have that in our current arsenal. -void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root, InventoryObjectList& contents) -{ - if (!inventory_root) - { - return; - } - // Create a visible root category. - LLTaskInvFVBridge* bridge = NULL; - bridge = LLTaskInvFVBridge::createObjectBridge(this, inventory_root); - if(bridge) - { - LLFolderViewFolder* new_folder = NULL; - LLFolderViewFolder::Params p; - p.name = inventory_root->getName(); - p.icon = LLUI::getUIImage("Inv_FolderClosed"); - p.icon_open = LLUI::getUIImage("Inv_FolderOpen"); - p.root = mFolders; - p.listener = bridge; - new_folder = LLUICtrlFactory::create<LLFolderViewFolder>(p); - new_folder->addToFolder(mFolders, mFolders); - new_folder->toggleOpen(); - - createViewsForCategory(&contents, inventory_root, new_folder); - } -} - -typedef std::pair<LLInventoryObject*, LLFolderViewFolder*> obj_folder_pair; - -void LLPanelObjectInventory::createViewsForCategory(InventoryObjectList* inventory, - LLInventoryObject* parent, - LLFolderViewFolder* folder) -{ - // Find all in the first pass - LLDynamicArray<obj_folder_pair*> child_categories; - LLTaskInvFVBridge* bridge; - LLFolderViewItem* view; - - InventoryObjectList::iterator it = inventory->begin(); - InventoryObjectList::iterator end = inventory->end(); - for( ; it != end; ++it) - { - LLInventoryObject* obj = *it; - - if(parent->getUUID() == obj->getParentUUID()) - { - bridge = LLTaskInvFVBridge::createObjectBridge(this, obj); - if(!bridge) - { - continue; - } - if(LLAssetType::AT_CATEGORY == obj->getType()) - { - LLFolderViewFolder::Params p; - p.name = obj->getName(); - p.icon = LLUI::getUIImage("Inv_FolderClosed"); - p.icon_open = LLUI::getUIImage("Inv_FolderOpen"); - p.root = mFolders; - p.listener = bridge; - view = LLUICtrlFactory::create<LLFolderViewFolder>(p); - child_categories.put(new obj_folder_pair(obj, - (LLFolderViewFolder*)view)); - } - else - { - LLFolderViewItem::Params params; - params.name(obj->getName()); - params.icon(bridge->getIcon()); - params.creation_date(bridge->getCreationDate()); - params.root(mFolders); - params.listener(bridge); - params.rect(LLRect()); - view = LLUICtrlFactory::create<LLFolderViewItem> (params); - } - view->addToFolder(folder, mFolders); - } - } - - // now, for each category, do the second pass - for(S32 i = 0; i < child_categories.count(); i++) - { - createViewsForCategory(inventory, child_categories[i]->first, - child_categories[i]->second ); - delete child_categories[i]; - } -} - -void LLPanelObjectInventory::refresh() -{ - //llinfos << "LLPanelObjectInventory::refresh()" << llendl; - BOOL has_inventory = FALSE; - const BOOL non_root_ok = TRUE; - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(NULL, non_root_ok); - if(node) - { - LLViewerObject* object = node->getObject(); - if(object && ((LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1) - || (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1))) - { - // determine if we need to make a request. Start with a - // default based on if we have inventory at all. - BOOL make_request = !mHaveInventory; - - // If the task id is different than what we've stored, - // then make the request. - if(mTaskUUID != object->mID) - { - mTaskUUID = object->mID; - make_request = TRUE; - - // This is a new object so pre-emptively clear the contents - // Otherwise we show the old stuff until the update comes in - clearContents(); - - // Register for updates from this object, - registerVOInventoryListener(object,NULL); - } - - // Based on the node information, we may need to dirty the - // object inventory and get it again. - if(node->mValid) - { - if(node->mInventorySerial != object->getInventorySerial() || object->isInventoryDirty()) - { - make_request = TRUE; - } - } - - // do the request if necessary. - if(make_request) - { - requestVOInventory(); - } - has_inventory = TRUE; - } - } - if(!has_inventory) - { - mTaskUUID = LLUUID::null; - removeVOInventoryListener(); - clearContents(); - } - //llinfos << "LLPanelObjectInventory::refresh() " << mTaskUUID << llendl; -} - -void LLPanelObjectInventory::removeSelectedItem() -{ - if(mFolders) - { - mFolders->removeSelectedItems(); - } -} - -void LLPanelObjectInventory::startRenamingSelectedItem() -{ - if(mFolders) - { - mFolders->startRenamingSelectedItem(); - } -} - -void LLPanelObjectInventory::draw() -{ - LLPanel::draw(); - - if(mIsInventoryEmpty) - { - if((LLUUID::null != mTaskUUID) && (!mHaveInventory)) - { - LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("LoadingContents"), 0, - (S32)(getRect().getWidth() * 0.5f), - 10, - LLColor4( 1, 1, 1, 1 ), - LLFontGL::HCENTER, - LLFontGL::BOTTOM); - } - else if(mHaveInventory) - { - LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("NoContents"), 0, - (S32)(getRect().getWidth() * 0.5f), - 10, - LLColor4( 1, 1, 1, 1 ), - LLFontGL::HCENTER, - LLFontGL::BOTTOM); - } - } -} - -void LLPanelObjectInventory::deleteAllChildren() -{ - mScroller = NULL; - mFolders = NULL; - LLView::deleteAllChildren(); -} - -BOOL LLPanelObjectInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg) -{ - if (mFolders && mHaveInventory) - { - LLFolderViewItem* folderp = mFolders->getNextFromChild(NULL); - if (!folderp) - { - return FALSE; - } - // Try to pass on unmodified mouse coordinates - S32 local_x = x - mFolders->getRect().mLeft; - S32 local_y = y - mFolders->getRect().mBottom; - - if (mFolders->pointInView(local_x, local_y)) - { - return mFolders->handleDragAndDrop(local_x, local_y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - } - else - { - //force mouse coordinates to be inside folder rectangle - return mFolders->handleDragAndDrop(5, 1, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - } - } - else - { - return FALSE; - } -} - -//static -void LLPanelObjectInventory::idle(void* user_data) -{ - LLPanelObjectInventory* self = (LLPanelObjectInventory*)user_data; - - - if (self->mInventoryNeedsUpdate) - { - self->updateInventory(); - } -} +/** + * @file llsidepanelinventory.cpp + * @brief LLPanelObjectInventory class implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +//***************************************************************************** +// +// Implementation of the panel inventory - used to view and control a +// task's inventory. +// +//***************************************************************************** + +#include "llviewerprecompiledheaders.h" + +#include "llpanelobjectinventory.h" + +#include "roles_constants.h" + +#include "llagent.h" +#include "llcallbacklist.h" +#include "llfloaterbuycurrency.h" +#include "llfloaterreg.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llpreviewanim.h" +#include "llpreviewgesture.h" +#include "llpreviewnotecard.h" +#include "llpreviewscript.h" +#include "llpreviewsound.h" +#include "llpreviewtexture.h" +#include "llscrollcontainer.h" +#include "llselectmgr.h" +#include "llsidetray.h" +#include "llstatusbar.h" +#include "lltrans.h" +#include "llviewerregion.h" +#include "llviewerobjectlist.h" +#include "llviewermessage.h" + + +///---------------------------------------------------------------------------- +/// Class LLTaskInvFVBridge +///---------------------------------------------------------------------------- + +class LLTaskInvFVBridge : public LLFolderViewEventListener +{ +protected: + LLUUID mUUID; + std::string mName; + mutable std::string mDisplayName; + LLPanelObjectInventory* mPanel; + U32 mFlags; + + LLInventoryItem* findItem() const; + +public: + LLTaskInvFVBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + U32 flags=0); + virtual ~LLTaskInvFVBridge( void ) {} + + virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } + virtual std::string getLabelSuffix() const { return LLStringUtil::null; } + + static LLTaskInvFVBridge* createObjectBridge(LLPanelObjectInventory* panel, + LLInventoryObject* object); + void showProperties(); + void buyItem(); + S32 getPrice(); + static bool commitBuyItem(const LLSD& notification, const LLSD& response); + + // LLFolderViewEventListener functionality + virtual const std::string& getName() const; + virtual const std::string& getDisplayName() const; + virtual PermissionMask getPermissionMask() const { return PERM_NONE; } + /*virtual*/ LLAssetType::EType getPreferredType() const { return LLAssetType::AT_NONE; } + virtual const LLUUID& getUUID() const { return mUUID; } + virtual time_t getCreationDate() const; + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void closeItem() {} + virtual void previewItem(); + virtual void selectItem() {} + virtual BOOL isItemRenameable() const; + virtual BOOL renameItem(const std::string& new_name); + virtual BOOL isItemMovable() const; + virtual BOOL isItemRemovable(); + virtual BOOL removeItem(); + virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch); + virtual void move(LLFolderViewEventListener* parent_listener); + virtual BOOL isItemCopyable() const; + virtual BOOL copyToClipboard() const; + virtual void cutToClipboard(); + virtual BOOL isClipboardPasteable() const; + virtual void pasteFromClipboard(); + virtual void pasteLinkFromClipboard(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual BOOL isUpToDate() const { return TRUE; } + virtual BOOL hasChildren() const { return FALSE; } + virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } + // LLDragAndDropBridge functionality + virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; + virtual BOOL dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data); +}; + +LLTaskInvFVBridge::LLTaskInvFVBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + U32 flags): + mUUID(uuid), + mName(name), + mPanel(panel), + mFlags(flags) +{ + +} + +LLInventoryItem* LLTaskInvFVBridge::findItem() const +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + return (LLInventoryItem*)(object->getInventoryObject(mUUID)); + } + return NULL; +} + +void LLTaskInvFVBridge::showProperties() +{ + LLSD key; + key["object"] = mPanel->getTaskUUID(); + key["id"] = mUUID; + LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); + + /* + LLFloaterProperties* floater = LLFloaterReg::showTypedInstance<LLFloaterProperties>("properties", mUUID); + if (floater) + { + floater->setObjectID(mPanel->getTaskUUID()); + } + */ +} + +struct LLBuyInvItemData +{ + LLUUID mTaskID; + LLUUID mItemID; + LLAssetType::EType mType; + + LLBuyInvItemData(const LLUUID& task, + const LLUUID& item, + LLAssetType::EType type) : + mTaskID(task), mItemID(item), mType(type) + {} +}; + +void LLTaskInvFVBridge::buyItem() +{ + llinfos << "LLTaskInvFVBridge::buyItem()" << llendl; + LLInventoryItem* item = findItem(); + if(!item || !item->getSaleInfo().isForSale()) return; + LLBuyInvItemData* inv = new LLBuyInvItemData(mPanel->getTaskUUID(), + mUUID, + item->getType()); + + const LLSaleInfo& sale_info = item->getSaleInfo(); + const LLPermissions& perm = item->getPermissions(); + const std::string owner_name; // no owner name currently... FIXME? + + LLViewerObject* obj; + if( ( obj = gObjectList.findObject( mPanel->getTaskUUID() ) ) && obj->isAttachment() ) + { + LLNotifications::instance().add("Cannot_Purchase_an_Attachment"); + llinfos << "Attempt to purchase an attachment" << llendl; + delete inv; + } + else + { + LLSD args; + args["PRICE"] = llformat("%d",sale_info.getSalePrice()); + args["OWNER"] = owner_name; + if (sale_info.getSaleType() != LLSaleInfo::FS_CONTENTS) + { + U32 next_owner_mask = perm.getMaskNextOwner(); + args["MODIFYPERM"] = LLNotifications::instance().getGlobalString((next_owner_mask & PERM_MODIFY) ? "PermYes" : "PermNo"); + args["COPYPERM"] = LLNotifications::instance().getGlobalString((next_owner_mask & PERM_COPY) ? "PermYes" : "PermNo"); + args["RESELLPERM"] = LLNotifications::instance().getGlobalString((next_owner_mask & PERM_TRANSFER) ? "PermYes" : "PermNo"); + } + + std::string alertdesc; + switch(sale_info.getSaleType()) + { + case LLSaleInfo::FS_ORIGINAL: + alertdesc = owner_name.empty() ? "BuyOriginalNoOwner" : "BuyOriginal"; + break; + case LLSaleInfo::FS_CONTENTS: + alertdesc = owner_name.empty() ? "BuyContentsNoOwner" : "BuyContents"; + break; + case LLSaleInfo::FS_COPY: + default: + alertdesc = owner_name.empty() ? "BuyCopyNoOwner" : "BuyCopy"; + break; + } + + LLSD payload; + payload["task_id"] = inv->mTaskID; + payload["item_id"] = inv->mItemID; + payload["type"] = inv->mType; + LLNotifications::instance().add(alertdesc, args, payload, LLTaskInvFVBridge::commitBuyItem); + } +} + +S32 LLTaskInvFVBridge::getPrice() +{ + LLInventoryItem* item = findItem(); + if(item) + { + return item->getSaleInfo().getSalePrice(); + } + else + { + return -1; + } +} + +// static +bool LLTaskInvFVBridge::commitBuyItem(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if(0 == option) + { + LLViewerObject* object = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); + if(!object || !object->getRegion()) return false; + + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_BuyObjectInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Data); + msg->addUUIDFast(_PREHASH_ObjectID, notification["payload"]["task_id"].asUUID()); + msg->addUUIDFast(_PREHASH_ItemID, notification["payload"]["item_id"].asUUID()); + msg->addUUIDFast(_PREHASH_FolderID, + gInventory.findCategoryUUIDForType((LLAssetType::EType)notification["payload"]["type"].asInteger())); + msg->sendReliable(object->getRegion()->getHost()); + } + return false; +} + +const std::string& LLTaskInvFVBridge::getName() const +{ + return mName; +} + +const std::string& LLTaskInvFVBridge::getDisplayName() const +{ + LLInventoryItem* item = findItem(); + if(item) + { + mDisplayName.assign(item->getName()); + + const LLPermissions& perm(item->getPermissions()); + BOOL copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE); + BOOL mod = gAgent.allowOperation(PERM_MODIFY, perm, GP_OBJECT_MANIPULATE); + BOOL xfer = gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE); + + if(!copy) + { + mDisplayName.append(" (no copy)"); + } + if(!mod) + { + mDisplayName.append(" (no modify)"); + } + if(!xfer) + { + mDisplayName.append(" (no transfer)"); + } + } + + return mDisplayName; +} + +// BUG: No creation dates for task inventory +time_t LLTaskInvFVBridge::getCreationDate() const +{ + return 0; +} + +LLUIImagePtr LLTaskInvFVBridge::getIcon() const +{ + BOOL item_is_multi = FALSE; + if ( mFlags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) + { + item_is_multi = TRUE; + } + + return get_item_icon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi ); +} + +void LLTaskInvFVBridge::openItem() +{ + // no-op. + lldebugs << "LLTaskInvFVBridge::openItem()" << llendl; +} + +void LLTaskInvFVBridge::previewItem() +{ + openItem(); +} + +BOOL LLTaskInvFVBridge::isItemRenameable() const +{ + if(gAgent.isGodlike()) return TRUE; + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + LLInventoryItem* item; + item = (LLInventoryItem*)(object->getInventoryObject(mUUID)); + if(item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), + GP_OBJECT_MANIPULATE, GOD_LIKE)) + { + return TRUE; + } + } + return FALSE; +} + +BOOL LLTaskInvFVBridge::renameItem(const std::string& new_name) +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + LLViewerInventoryItem* item = NULL; + item = (LLViewerInventoryItem*)object->getInventoryObject(mUUID); + if(item && (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), + GP_OBJECT_MANIPULATE, GOD_LIKE))) + { + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + new_item->rename(new_name); + object->updateInventory( + new_item, + TASK_INVENTORY_ITEM_KEY, + false); + } + } + return TRUE; +} + +BOOL LLTaskInvFVBridge::isItemMovable() const +{ + //LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + //if(object && (object->permModify() || gAgent.isGodlike())) + //{ + // return TRUE; + //} + //return FALSE; + return TRUE; +} + +BOOL LLTaskInvFVBridge::isItemRemovable() +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object + && (object->permModify() || object->permYouOwner())) + { + return TRUE; + } + return FALSE; +} + +bool remove_task_inventory_callback(const LLSD& notification, const LLSD& response, LLPanelObjectInventory* panel) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLViewerObject* object = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); + if(option == 0 && object) + { + // yes + LLSD::array_const_iterator list_end = notification["payload"]["inventory_ids"].endArray(); + for (LLSD::array_const_iterator list_it = notification["payload"]["inventory_ids"].beginArray(); + list_it != list_end; + ++list_it) + { + object->removeInventory(list_it->asUUID()); + } + + // refresh the UI. + panel->refresh(); + } + return false; +} + +// helper for remove +// ! REFACTOR ! two_uuids_list_t is also defined in llinevntorybridge.h, but differently. +typedef std::pair<LLUUID, std::list<LLUUID> > panel_two_uuids_list_t; +typedef std::pair<LLPanelObjectInventory*, panel_two_uuids_list_t> remove_data_t; +BOOL LLTaskInvFVBridge::removeItem() +{ + if(isItemRemovable() && mPanel) + { + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + if(object->permModify()) + { + // just do it. + object->removeInventory(mUUID); + return TRUE; + } + else + { + remove_data_t* data = new remove_data_t; + data->first = mPanel; + data->second.first = mPanel->getTaskUUID(); + data->second.second.push_back(mUUID); + LLSD payload; + payload["task_id"] = mPanel->getTaskUUID(); + payload["inventory_ids"].append(mUUID); + LLNotifications::instance().add("RemoveItemWarn", LLSD(), payload, boost::bind(&remove_task_inventory_callback, _1, _2, mPanel)); + return FALSE; + } + } + } + return FALSE; +} + +void LLTaskInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) +{ + if (!mPanel) + { + return; + } + + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if (!object) + { + return; + } + + if (!object->permModify()) + { + LLSD payload; + payload["task_id"] = mPanel->getTaskUUID(); + for (S32 i = 0; i < (S32)batch.size(); i++) + { + LLTaskInvFVBridge* itemp = (LLTaskInvFVBridge*)batch[i]; + payload["inventory_ids"].append(itemp->getUUID()); + } + LLNotifications::instance().add("RemoveItemWarn", LLSD(), payload, boost::bind(&remove_task_inventory_callback, _1, _2, mPanel)); + + } + else + { + for (S32 i = 0; i < (S32)batch.size(); i++) + { + LLTaskInvFVBridge* itemp = (LLTaskInvFVBridge*)batch[i]; + + if(itemp->isItemRemovable()) + { + // just do it. + object->removeInventory(itemp->getUUID()); + } + } + } +} + +void LLTaskInvFVBridge::move(LLFolderViewEventListener* parent_listener) +{ +} + +BOOL LLTaskInvFVBridge::isItemCopyable() const +{ + LLInventoryItem* item = findItem(); + if(!item) return FALSE; + return gAgent.allowOperation(PERM_COPY, item->getPermissions(), + GP_OBJECT_MANIPULATE); +} + +BOOL LLTaskInvFVBridge::copyToClipboard() const +{ + return FALSE; +} + +void LLTaskInvFVBridge::cutToClipboard() +{ +} + +BOOL LLTaskInvFVBridge::isClipboardPasteable() const +{ + return FALSE; +} + +void LLTaskInvFVBridge::pasteFromClipboard() +{ +} + +void LLTaskInvFVBridge::pasteLinkFromClipboard() +{ +} + +BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const +{ + //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; + if(mPanel) + { + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + LLInventoryItem* inv = NULL; + if((inv = (LLInventoryItem*)object->getInventoryObject(mUUID))) + { + const LLPermissions& perm = inv->getPermissions(); + bool can_copy = gAgent.allowOperation(PERM_COPY, perm, + GP_OBJECT_MANIPULATE); + if (object->isAttachment() && !can_copy) + { + //RN: no copy contents of attachments cannot be dragged out + // due to a race condition and possible exploit where + // attached objects do not update their inventory items + // when their contents are manipulated + return FALSE; + } + if((can_copy && perm.allowTransferTo(gAgent.getID())) + || object->permYouOwner()) +// || gAgent.isGodlike()) + + { + *type = LLAssetType::lookupDragAndDropType(inv->getType()); + + *id = inv->getUUID(); + return TRUE; + } + } + } + } + return FALSE; +} + +BOOL LLTaskInvFVBridge::dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data) +{ + //llinfos << "LLTaskInvFVBridge::dragOrDrop()" << llendl; + return FALSE; +} + +// virtual +void LLTaskInvFVBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if (action == "task_buy") + { + // Check the price of the item. + S32 price = getPrice(); + if (-1 == price) + { + llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + } + else + { + if (price > 0 && price > gStatusBar->getBalance()) + { + LLFloaterBuyCurrency::buyCurrency("This costs", price); + } + else + { + buyItem(); + } + } + } + else if (action == "task_open") + { + openItem(); + } + else if (action == "task_properties") + { + showProperties(); + } +} + +void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LLInventoryItem* item = findItem(); + std::vector<std::string> items; + std::vector<std::string> disabled_items; + + if (!item) + { + hide_context_entries(menu, items, disabled_items); + return; + } + + if(gAgent.allowOperation(PERM_OWNER, item->getPermissions(), + GP_OBJECT_MANIPULATE) + && item->getSaleInfo().isForSale()) + { + items.push_back(std::string("Task Buy")); + + std::string label= LLTrans::getString("Buy"); + // Check the price of the item. + S32 price = getPrice(); + if (-1 == price) + { + llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + } + else + { + std::ostringstream info; + info << LLTrans::getString("BuyforL$") << price; + label.assign(info.str()); + } + + const LLView::child_list_t *list = menu.getChildList(); + LLView::child_list_t::const_iterator itor; + for (itor = list->begin(); itor != list->end(); ++itor) + { + std::string name = (*itor)->getName(); + LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor); + if (name == "Task Buy" && menu_itemp) + { + menu_itemp->setLabel(label); + } + } + } + else + { + items.push_back(std::string("Task Open")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Task Open")); + } + } + items.push_back(std::string("Task Properties")); + if(isItemRenameable()) + { + items.push_back(std::string("Task Rename")); + } + if(isItemRemovable()) + { + items.push_back(std::string("Task Remove")); + } + + hide_context_entries(menu, items, disabled_items); +} + + +///---------------------------------------------------------------------------- +/// Class LLTaskFolderBridge +///---------------------------------------------------------------------------- + +class LLTaskCategoryBridge : public LLTaskInvFVBridge +{ +public: + LLTaskCategoryBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual const std::string& getDisplayName() const { return getName(); } + virtual BOOL isItemRenameable() const; + virtual BOOL renameItem(const std::string& new_name); + virtual BOOL isItemRemovable(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual BOOL hasChildren() const; + virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; + virtual BOOL dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data); +}; + +LLTaskCategoryBridge::LLTaskCategoryBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskCategoryBridge::getIcon() const +{ + return LLUI::getUIImage("Inv_FolderClosed"); +} + +BOOL LLTaskCategoryBridge::isItemRenameable() const +{ + return FALSE; +} + +BOOL LLTaskCategoryBridge::renameItem(const std::string& new_name) +{ + return FALSE; +} + +BOOL LLTaskCategoryBridge::isItemRemovable() +{ + return FALSE; +} + +void LLTaskCategoryBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + std::vector<std::string> items; + std::vector<std::string> disabled_items; + items.push_back(std::string("Task Open")); + hide_context_entries(menu, items, disabled_items); +} + +BOOL LLTaskCategoryBridge::hasChildren() const +{ + // return TRUE if we have or do know know if we have children. + // *FIX: For now, return FALSE - we will know for sure soon enough. + return FALSE; +} + +BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const +{ + //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; + if(mPanel) + { + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + LLInventoryItem* inv = NULL; + if((inv = (LLInventoryItem*)object->getInventoryObject(mUUID))) + { + const LLPermissions& perm = inv->getPermissions(); + bool can_copy = gAgent.allowOperation(PERM_COPY, perm, + GP_OBJECT_MANIPULATE); + if((can_copy && perm.allowTransferTo(gAgent.getID())) + || object->permYouOwner()) +// || gAgent.isGodlike()) + + { + *type = LLAssetType::lookupDragAndDropType(inv->getType()); + + *id = inv->getUUID(); + return TRUE; + } + } + } + } + return FALSE; +} + +BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data) +{ + //llinfos << "LLTaskCategoryBridge::dragOrDrop()" << llendl; + BOOL accept = FALSE; + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(object) + { + switch(cargo_type) + { + case DAD_CATEGORY: + accept = LLToolDragAndDrop::getInstance()->dadUpdateInventoryCategory(object,drop); + break; + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_LANDMARK: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_CLOTHING: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + case DAD_CALLINGCARD: + accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); + if(accept && drop) + { + LLToolDragAndDrop::dropInventory(object, + (LLViewerInventoryItem*)cargo_data, + LLToolDragAndDrop::getInstance()->getSource(), + LLToolDragAndDrop::getInstance()->getSourceID()); + } + break; + case DAD_SCRIPT: + // *HACK: In order to resolve SL-22177, we need to block + // drags from notecards and objects onto other + // objects. uncomment the simpler version when we have + // that right. + //accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); + if(LLToolDragAndDrop::isInventoryDropAcceptable( + object, (LLViewerInventoryItem*)cargo_data) + && (LLToolDragAndDrop::SOURCE_WORLD != LLToolDragAndDrop::getInstance()->getSource()) + && (LLToolDragAndDrop::SOURCE_NOTECARD != LLToolDragAndDrop::getInstance()->getSource())) + { + accept = TRUE; + } + if(accept && drop) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)cargo_data; + // rez in the script active by default, rez in + // inactive if the control key is being held down. + BOOL active = ((mask & MASK_CONTROL) == 0); + LLToolDragAndDrop::dropScript(object, item, active, + LLToolDragAndDrop::getInstance()->getSource(), + LLToolDragAndDrop::getInstance()->getSourceID()); + } + break; + default: + break; + } + } + return accept; +} + +///---------------------------------------------------------------------------- +/// Class LLTaskTextureBridge +///---------------------------------------------------------------------------- + +class LLTaskTextureBridge : public LLTaskInvFVBridge +{ +public: + LLTaskTextureBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + LLInventoryType::EType it); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); +protected: + LLInventoryType::EType mInventoryType; +}; + +LLTaskTextureBridge::LLTaskTextureBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + LLInventoryType::EType it) : + LLTaskInvFVBridge(panel, uuid, name), + mInventoryType(it) +{ +} + +LLUIImagePtr LLTaskTextureBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_TEXTURE, mInventoryType, 0, FALSE); +} + +void LLTaskTextureBridge::openItem() +{ + llinfos << "LLTaskTextureBridge::openItem()" << llendl; + LLPreviewTexture* preview = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); + if(preview) + { + preview->setObjectID(mPanel->getTaskUUID()); + } +} + + +///---------------------------------------------------------------------------- +/// Class LLTaskSoundBridge +///---------------------------------------------------------------------------- + +class LLTaskSoundBridge : public LLTaskInvFVBridge +{ +public: + LLTaskSoundBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + static void openSoundPreview(void* data); +}; + +LLTaskSoundBridge::LLTaskSoundBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskSoundBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); +} + +void LLTaskSoundBridge::openItem() +{ + openSoundPreview((void*)this); +} + +void LLTaskSoundBridge::openSoundPreview(void* data) +{ + LLTaskSoundBridge* self = (LLTaskSoundBridge*)data; + if(!self) + return; + + LLPreviewSound* preview = LLFloaterReg::showTypedInstance<LLPreviewSound>("preview_sound", LLSD(self->mUUID), TAKE_FOCUS_YES); + if (preview) + { + preview->setObjectID(self->mPanel->getTaskUUID()); + } +} + +// virtual +void LLTaskSoundBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if (action == "task_play") + { + LLInventoryItem* item = findItem(); + if(item) + { + send_sound_trigger(item->getAssetUUID(), 1.0); + } + } + LLTaskInvFVBridge::performAction(folder, model, action); +} + +void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LLInventoryItem* item = findItem(); + if(!item) return; + std::vector<std::string> items; + std::vector<std::string> disabled_items; + + if(item->getPermissions().getOwner() != gAgent.getID() + && item->getSaleInfo().isForSale()) + { + items.push_back(std::string("Task Buy")); + + std::string label= LLTrans::getString("Buy"); + // Check the price of the item. + S32 price = getPrice(); + if (-1 == price) + { + llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + } + else + { + std::ostringstream info; + info << LLTrans::getString("BuyforL$") << price; + label.assign(info.str()); + } + + const LLView::child_list_t *list = menu.getChildList(); + LLView::child_list_t::const_iterator itor; + for (itor = list->begin(); itor != list->end(); ++itor) + { + std::string name = (*itor)->getName(); + LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor); + if (name == "Task Buy" && menu_itemp) + { + menu_itemp->setLabel(label); + } + } + } + else + { + items.push_back(std::string("Task Open")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Task Open")); + } + } + items.push_back(std::string("Task Properties")); + if(isItemRenameable()) + { + items.push_back(std::string("Task Rename")); + } + if(isItemRemovable()) + { + items.push_back(std::string("Task Remove")); + } + + items.push_back(std::string("Task Play")); + + + hide_context_entries(menu, items, disabled_items); +} + +///---------------------------------------------------------------------------- +/// Class LLTaskLandmarkBridge +///---------------------------------------------------------------------------- + +class LLTaskLandmarkBridge : public LLTaskInvFVBridge +{ +public: + LLTaskLandmarkBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; +}; + +LLTaskLandmarkBridge::LLTaskLandmarkBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskLandmarkBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, 0, FALSE); +} + + +///---------------------------------------------------------------------------- +/// Class LLTaskCallingCardBridge +///---------------------------------------------------------------------------- + +class LLTaskCallingCardBridge : public LLTaskInvFVBridge +{ +public: + LLTaskCallingCardBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual BOOL isItemRenameable() const; + virtual BOOL renameItem(const std::string& new_name); +}; + +LLTaskCallingCardBridge::LLTaskCallingCardBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskCallingCardBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, 0, FALSE); +} + +BOOL LLTaskCallingCardBridge::isItemRenameable() const +{ + return FALSE; +} + +BOOL LLTaskCallingCardBridge::renameItem(const std::string& new_name) +{ + return FALSE; +} + + +///---------------------------------------------------------------------------- +/// Class LLTaskScriptBridge +///---------------------------------------------------------------------------- + +class LLTaskScriptBridge : public LLTaskInvFVBridge +{ +public: + LLTaskScriptBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + //static BOOL enableIfCopyable( void* userdata ); +}; + +LLTaskScriptBridge::LLTaskScriptBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskScriptBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); +} + + +class LLTaskLSLBridge : public LLTaskScriptBridge +{ +public: + LLTaskLSLBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual void openItem(); + virtual BOOL removeItem(); + //virtual void buildContextMenu(LLMenuGL& menu); + + //static void copyToInventory(void* userdata); +}; + +LLTaskLSLBridge::LLTaskLSLBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskScriptBridge(panel, uuid, name) +{ +} + +void LLTaskLSLBridge::openItem() +{ + llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(!object || object->isInventoryPending()) + { + return; + } + LLLiveLSLEditor* preview = LLFloaterReg::showTypedInstance<LLLiveLSLEditor>("preview_scriptedit", LLSD(mUUID), TAKE_FOCUS_YES); + if (preview && (object->permModify() || gAgent.isGodlike())) + { + preview->setObjectID(mPanel->getTaskUUID()); + } +} + +BOOL LLTaskLSLBridge::removeItem() +{ + LLFloaterReg::hideInstance("preview_scriptedit", LLSD(mUUID)); + return LLTaskInvFVBridge::removeItem(); +} + +///---------------------------------------------------------------------------- +/// Class LLTaskObjectBridge +///---------------------------------------------------------------------------- + +class LLTaskObjectBridge : public LLTaskInvFVBridge +{ +public: + LLTaskObjectBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; +}; + +LLTaskObjectBridge::LLTaskObjectBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskObjectBridge::getIcon() const +{ + BOOL item_is_multi = FALSE; + if ( mFlags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) + { + item_is_multi = TRUE; + } + + return get_item_icon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi); +} + +///---------------------------------------------------------------------------- +/// Class LLTaskNotecardBridge +///---------------------------------------------------------------------------- + +class LLTaskNotecardBridge : public LLTaskInvFVBridge +{ +public: + LLTaskNotecardBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual BOOL removeItem(); +}; + +LLTaskNotecardBridge::LLTaskNotecardBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskNotecardBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); +} + +void LLTaskNotecardBridge::openItem() +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(!object || object->isInventoryPending()) + { + return; + } + if(object->permModify() || gAgent.isGodlike()) + { + LLPreviewNotecard* preview = LLFloaterReg::showTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(mUUID), TAKE_FOCUS_YES); + if (preview) + { + preview->setObjectID(mPanel->getTaskUUID()); + } + } +} + +BOOL LLTaskNotecardBridge::removeItem() +{ + LLFloaterReg::hideInstance("preview_notecard", LLSD(mUUID)); + return LLTaskInvFVBridge::removeItem(); +} + +///---------------------------------------------------------------------------- +/// Class LLTaskGestureBridge +///---------------------------------------------------------------------------- + +class LLTaskGestureBridge : public LLTaskInvFVBridge +{ +public: + LLTaskGestureBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual BOOL removeItem(); +}; + +LLTaskGestureBridge::LLTaskGestureBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskGestureBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); +} + +void LLTaskGestureBridge::openItem() +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(!object || object->isInventoryPending()) + { + return; + } + LLPreviewGesture::show(mUUID, mPanel->getTaskUUID()); +} + +BOOL LLTaskGestureBridge::removeItem() +{ + // Don't need to deactivate gesture because gestures inside objects can never be active. + LLFloaterReg::hideInstance("preview_gesture", LLSD(mUUID)); + return LLTaskInvFVBridge::removeItem(); +} + +///---------------------------------------------------------------------------- +/// Class LLTaskAnimationBridge +///---------------------------------------------------------------------------- + +class LLTaskAnimationBridge : public LLTaskInvFVBridge +{ +public: + LLTaskAnimationBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual BOOL removeItem(); +}; + +LLTaskAnimationBridge::LLTaskAnimationBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskAnimationBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); +} + +void LLTaskAnimationBridge::openItem() +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(!object || object->isInventoryPending()) + { + return; + } + + LLPreviewAnim* preview = LLFloaterReg::showTypedInstance<LLPreviewAnim>("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); + if (preview && (object->permModify() || gAgent.isGodlike())) + { + preview->setObjectID(mPanel->getTaskUUID()); + } +} + +BOOL LLTaskAnimationBridge::removeItem() +{ + LLFloaterReg::hideInstance("preview_anim", LLSD(mUUID)); + return LLTaskInvFVBridge::removeItem(); +} + +///---------------------------------------------------------------------------- +/// Class LLTaskWearableBridge +///---------------------------------------------------------------------------- + +class LLTaskWearableBridge : public LLTaskInvFVBridge +{ +public: + LLTaskWearableBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + LLAssetType::EType asset_type, + U32 flags); + + virtual LLUIImagePtr getIcon() const; + +protected: + LLAssetType::EType mAssetType; +}; + +LLTaskWearableBridge::LLTaskWearableBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name, + LLAssetType::EType asset_type, + U32 flags) : + LLTaskInvFVBridge(panel, uuid, name, flags), + mAssetType( asset_type ) +{ +} + +LLUIImagePtr LLTaskWearableBridge::getIcon() const +{ + return get_item_icon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE ); +} + + +///---------------------------------------------------------------------------- +/// LLTaskInvFVBridge impl +//---------------------------------------------------------------------------- + +LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* panel, + LLInventoryObject* object) +{ + LLTaskInvFVBridge* new_bridge = NULL; + LLAssetType::EType type = object->getType(); + LLInventoryItem* item = NULL; + switch(type) + { + case LLAssetType::AT_TEXTURE: + item = (LLInventoryItem*)object; + new_bridge = new LLTaskTextureBridge(panel, + object->getUUID(), + object->getName(), + item->getInventoryType()); + break; + case LLAssetType::AT_SOUND: + new_bridge = new LLTaskSoundBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_LANDMARK: + new_bridge = new LLTaskLandmarkBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_CALLINGCARD: + new_bridge = new LLTaskCallingCardBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_SCRIPT: + // OLD SCRIPTS DEPRECATED - JC + llwarns << "Old script" << llendl; + //new_bridge = new LLTaskOldScriptBridge(panel, + // object->getUUID(), + // object->getName()); + break; + case LLAssetType::AT_OBJECT: + new_bridge = new LLTaskObjectBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_NOTECARD: + new_bridge = new LLTaskNotecardBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_ANIMATION: + new_bridge = new LLTaskAnimationBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_GESTURE: + new_bridge = new LLTaskGestureBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + item = (LLInventoryItem*)object; + new_bridge = new LLTaskWearableBridge(panel, + object->getUUID(), + object->getName(), + type, + item->getFlags()); + break; + case LLAssetType::AT_CATEGORY: + case LLAssetType::AT_FAVORITE: + new_bridge = new LLTaskCategoryBridge(panel, + object->getUUID(), + object->getName()); + break; + case LLAssetType::AT_LSL_TEXT: + new_bridge = new LLTaskLSLBridge(panel, + object->getUUID(), + object->getName()); + break; + + break; + default: + llinfos << "Unhandled inventory type (llassetstorage.h): " + << (S32)type << llendl; + break; + } + return new_bridge; +} + + +///---------------------------------------------------------------------------- +/// Class LLPanelObjectInventory +///---------------------------------------------------------------------------- + +static LLDefaultChildRegistry::Register<LLPanelObjectInventory> r("panel_inventory_object"); + +void do_nothing() +{ +} + +// Default constructor +LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Params& p) : + LLPanel(p), + mScroller(NULL), + mFolders(NULL), + mHaveInventory(FALSE), + mIsInventoryEmpty(TRUE), + mInventoryNeedsUpdate(FALSE) +{ + // Setup context menu callbacks + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&do_nothing)); + mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&do_nothing)); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&do_nothing)); +} + +// Destroys the object +LLPanelObjectInventory::~LLPanelObjectInventory() +{ + if (!gIdleCallbacks.deleteFunction(idle, this)) + { + llwarns << "LLPanelObjectInventory::~LLPanelObjectInventory() failed to delete callback" << llendl; + } +} + +BOOL LLPanelObjectInventory::postBuild() +{ + // clear contents and initialize menus, sets up mFolders + reset(); + + // Register an idle update callback + gIdleCallbacks.addFunction(idle, this); + + return TRUE; +} + +void LLPanelObjectInventory::doToSelected(const LLSD& userdata) +{ + mFolders->doToSelected(&gInventory, userdata); +} + +void LLPanelObjectInventory::clearContents() +{ + mHaveInventory = FALSE; + mIsInventoryEmpty = TRUE; + if (LLToolDragAndDrop::getInstance() && LLToolDragAndDrop::getInstance()->getSource() == LLToolDragAndDrop::SOURCE_WORLD) + { + LLToolDragAndDrop::getInstance()->endDrag(); + } + + if( mScroller ) + { + // removes mFolders + removeChild( mScroller ); //*TODO: Really shouldn't do this during draw()/refresh() + mScroller->die(); + mScroller = NULL; + mFolders = NULL; + } +} + + +void LLPanelObjectInventory::reset() +{ + clearContents(); + + setBorderVisible(FALSE); + + mCommitCallbackRegistrar.pushScope(); // push local callbacks + + LLRect dummy_rect(0, 1, 1, 0); + LLFolderView::Params p; + p.name = "task inventory"; + p.task_id = getTaskUUID(); + p.parent_panel = this; + mFolders = LLUICtrlFactory::create<LLFolderView>(p); + // this ensures that we never say "searching..." or "no items found" + mFolders->getFilter()->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); + + LLRect scroller_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + LLScrollContainer::Params scroll_p; + scroll_p.name("task inventory scroller"); + scroll_p.rect(scroller_rect); + scroll_p.follows.flags(FOLLOWS_ALL); + mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_p); + addChild(mScroller); + mScroller->addChild(mFolders); + + mFolders->setScrollContainer( mScroller ); + + mCommitCallbackRegistrar.popScope(); +} + +void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, + InventoryObjectList* inventory, + S32 serial_num, + void* data) +{ + if(!object) return; + + //llinfos << "invetnory arrived: \n" + // << " panel UUID: " << panel->mTaskUUID << "\n" + // << " task UUID: " << object->mID << llendl; + if(mTaskUUID == object->mID) + { + mInventoryNeedsUpdate = TRUE; + } + + // refresh any properties floaters that are hanging around. + if(inventory) + { + for (InventoryObjectList::const_iterator iter = inventory->begin(); + iter != inventory->end(); ) + { + LLInventoryObject* item = *iter++; + LLFloaterProperties* floater = LLFloaterReg::findTypedInstance<LLFloaterProperties>("properites", item->getUUID()); + if(floater) + { + floater->refresh(); + } + } + } +} + +void LLPanelObjectInventory::updateInventory() +{ + //llinfos << "inventory arrived: \n" + // << " panel UUID: " << panel->mTaskUUID << "\n" + // << " task UUID: " << object->mID << llendl; + // We're still interested in this task's inventory. + std::set<LLUUID> selected_items; + BOOL inventory_has_focus = FALSE; + if (mHaveInventory && mFolders->getNumSelectedDescendants()) + { + mFolders->getSelectionList(selected_items); + inventory_has_focus = gFocusMgr.childHasKeyboardFocus(mFolders); + } + + reset(); + + LLViewerObject* objectp = gObjectList.findObject(mTaskUUID); + if (objectp) + { + LLInventoryObject* inventory_root = objectp->getInventoryRoot(); + InventoryObjectList contents; + objectp->getInventoryContents(contents); + if (inventory_root) + { + createFolderViews(inventory_root, contents); + mHaveInventory = TRUE; + mIsInventoryEmpty = FALSE; + mFolders->setEnabled(TRUE); + } + else + { + // TODO: create an empty inventory + mIsInventoryEmpty = TRUE; + mHaveInventory = TRUE; + } + } + else + { + // TODO: create an empty inventory + mIsInventoryEmpty = TRUE; + mHaveInventory = TRUE; + } + + // restore previous selection + std::set<LLUUID>::iterator selection_it; + BOOL first_item = TRUE; + for (selection_it = selected_items.begin(); selection_it != selected_items.end(); ++selection_it) + { + LLFolderViewItem* selected_item = mFolders->getItemByID(*selection_it); + if (selected_item) + { + //HACK: "set" first item then "change" each other one to get keyboard focus right + if (first_item) + { + mFolders->setSelection(selected_item, TRUE, inventory_has_focus); + first_item = FALSE; + } + else + { + mFolders->changeSelection(selected_item, TRUE); + } + } + } + + mFolders->requestArrange(); + mInventoryNeedsUpdate = FALSE; +} + +// *FIX: This is currently a very expensive operation, because we have +// to iterate through the inventory one time for each category. This +// leads to an N^2 based on the category count. This could be greatly +// speeded with an efficient multimap implementation, but we don't +// have that in our current arsenal. +void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root, InventoryObjectList& contents) +{ + if (!inventory_root) + { + return; + } + // Create a visible root category. + LLTaskInvFVBridge* bridge = NULL; + bridge = LLTaskInvFVBridge::createObjectBridge(this, inventory_root); + if(bridge) + { + LLFolderViewFolder* new_folder = NULL; + LLFolderViewFolder::Params p; + p.name = inventory_root->getName(); + p.icon = LLUI::getUIImage("Inv_FolderClosed"); + p.icon_open = LLUI::getUIImage("Inv_FolderOpen"); + p.root = mFolders; + p.listener = bridge; + new_folder = LLUICtrlFactory::create<LLFolderViewFolder>(p); + new_folder->addToFolder(mFolders, mFolders); + new_folder->toggleOpen(); + + createViewsForCategory(&contents, inventory_root, new_folder); + } +} + +typedef std::pair<LLInventoryObject*, LLFolderViewFolder*> obj_folder_pair; + +void LLPanelObjectInventory::createViewsForCategory(InventoryObjectList* inventory, + LLInventoryObject* parent, + LLFolderViewFolder* folder) +{ + // Find all in the first pass + LLDynamicArray<obj_folder_pair*> child_categories; + LLTaskInvFVBridge* bridge; + LLFolderViewItem* view; + + InventoryObjectList::iterator it = inventory->begin(); + InventoryObjectList::iterator end = inventory->end(); + for( ; it != end; ++it) + { + LLInventoryObject* obj = *it; + + if(parent->getUUID() == obj->getParentUUID()) + { + bridge = LLTaskInvFVBridge::createObjectBridge(this, obj); + if(!bridge) + { + continue; + } + if(LLAssetType::AT_CATEGORY == obj->getType()) + { + LLFolderViewFolder::Params p; + p.name = obj->getName(); + p.icon = LLUI::getUIImage("Inv_FolderClosed"); + p.icon_open = LLUI::getUIImage("Inv_FolderOpen"); + p.root = mFolders; + p.listener = bridge; + view = LLUICtrlFactory::create<LLFolderViewFolder>(p); + child_categories.put(new obj_folder_pair(obj, + (LLFolderViewFolder*)view)); + } + else + { + LLFolderViewItem::Params params; + params.name(obj->getName()); + params.icon(bridge->getIcon()); + params.creation_date(bridge->getCreationDate()); + params.root(mFolders); + params.listener(bridge); + params.rect(LLRect()); + view = LLUICtrlFactory::create<LLFolderViewItem> (params); + } + view->addToFolder(folder, mFolders); + } + } + + // now, for each category, do the second pass + for(S32 i = 0; i < child_categories.count(); i++) + { + createViewsForCategory(inventory, child_categories[i]->first, + child_categories[i]->second ); + delete child_categories[i]; + } +} + +void LLPanelObjectInventory::refresh() +{ + //llinfos << "LLPanelObjectInventory::refresh()" << llendl; + BOOL has_inventory = FALSE; + const BOOL non_root_ok = TRUE; + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(NULL, non_root_ok); + if(node) + { + LLViewerObject* object = node->getObject(); + if(object && ((LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1) + || (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1))) + { + // determine if we need to make a request. Start with a + // default based on if we have inventory at all. + BOOL make_request = !mHaveInventory; + + // If the task id is different than what we've stored, + // then make the request. + if(mTaskUUID != object->mID) + { + mTaskUUID = object->mID; + make_request = TRUE; + + // This is a new object so pre-emptively clear the contents + // Otherwise we show the old stuff until the update comes in + clearContents(); + + // Register for updates from this object, + registerVOInventoryListener(object,NULL); + } + + // Based on the node information, we may need to dirty the + // object inventory and get it again. + if(node->mValid) + { + if(node->mInventorySerial != object->getInventorySerial() || object->isInventoryDirty()) + { + make_request = TRUE; + } + } + + // do the request if necessary. + if(make_request) + { + requestVOInventory(); + } + has_inventory = TRUE; + } + } + if(!has_inventory) + { + mTaskUUID = LLUUID::null; + removeVOInventoryListener(); + clearContents(); + } + //llinfos << "LLPanelObjectInventory::refresh() " << mTaskUUID << llendl; +} + +void LLPanelObjectInventory::removeSelectedItem() +{ + if(mFolders) + { + mFolders->removeSelectedItems(); + } +} + +void LLPanelObjectInventory::startRenamingSelectedItem() +{ + if(mFolders) + { + mFolders->startRenamingSelectedItem(); + } +} + +void LLPanelObjectInventory::draw() +{ + LLPanel::draw(); + + if(mIsInventoryEmpty) + { + if((LLUUID::null != mTaskUUID) && (!mHaveInventory)) + { + LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("LoadingContents"), 0, + (S32)(getRect().getWidth() * 0.5f), + 10, + LLColor4( 1, 1, 1, 1 ), + LLFontGL::HCENTER, + LLFontGL::BOTTOM); + } + else if(mHaveInventory) + { + LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("NoContents"), 0, + (S32)(getRect().getWidth() * 0.5f), + 10, + LLColor4( 1, 1, 1, 1 ), + LLFontGL::HCENTER, + LLFontGL::BOTTOM); + } + } +} + +void LLPanelObjectInventory::deleteAllChildren() +{ + mScroller = NULL; + mFolders = NULL; + LLView::deleteAllChildren(); +} + +BOOL LLPanelObjectInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg) +{ + if (mFolders && mHaveInventory) + { + LLFolderViewItem* folderp = mFolders->getNextFromChild(NULL); + if (!folderp) + { + return FALSE; + } + // Try to pass on unmodified mouse coordinates + S32 local_x = x - mFolders->getRect().mLeft; + S32 local_y = y - mFolders->getRect().mBottom; + + if (mFolders->pointInView(local_x, local_y)) + { + return mFolders->handleDragAndDrop(local_x, local_y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + else + { + //force mouse coordinates to be inside folder rectangle + return mFolders->handleDragAndDrop(5, 1, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + } + else + { + return FALSE; + } +} + +//static +void LLPanelObjectInventory::idle(void* user_data) +{ + LLPanelObjectInventory* self = (LLPanelObjectInventory*)user_data; + + + if (self->mInventoryNeedsUpdate) + { + self->updateInventory(); + } +} diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 7a39d8fabc433767389d9993cc2f48905a1b744c..6722bb212e5afc8c26e7f81f9d1726d97aef82f5 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -1,102 +1,102 @@ -/** - * @file llpanelobjectinventory.h - * @brief LLPanelObjectInventory class definition - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLPANELOBJECTINVENTORY_H -#define LL_LLPANELOBJECTINVENTORY_H - -#include "llvoinventorylistener.h" -#include "llpanel.h" - -#include "llinventory.h" - -class LLScrollContainer; -class LLFolderView; -class LLFolderViewFolder; -class LLViewerObject; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLPanelObjectInventory -// -// This class represents the panel used to view and control a -// particular task's inventory. -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener -{ -public: - // dummy param block for template registration purposes - struct Params : public LLPanel::Params {}; - - LLPanelObjectInventory(const Params&); - virtual ~LLPanelObjectInventory(); - - virtual BOOL postBuild(); - - void doToSelected(const LLSD& userdata); - - void refresh(); - const LLUUID& getTaskUUID() { return mTaskUUID;} - void removeSelectedItem(); - void startRenamingSelectedItem(); - - LLFolderView* getRootFolder() const { return mFolders; } - - virtual void draw(); - virtual void deleteAllChildren(); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); - - static void idle(void* user_data); - -protected: - void reset(); - /*virtual*/ void inventoryChanged(LLViewerObject* object, - InventoryObjectList* inventory, - S32 serial_num, - void* user_data); - void updateInventory(); - void createFolderViews(LLInventoryObject* inventory_root, InventoryObjectList& contents); - void createViewsForCategory(InventoryObjectList* inventory, - LLInventoryObject* parent, - LLFolderViewFolder* folder); - void clearContents(); - -private: - LLScrollContainer* mScroller; - LLFolderView* mFolders; - - LLUUID mTaskUUID; - BOOL mHaveInventory; - BOOL mIsInventoryEmpty; - BOOL mInventoryNeedsUpdate; -}; - -#endif // LL_LLPANELOBJECTINVENTORY_H +/** + * @file llpanelobjectinventory.h + * @brief LLPanelObjectInventory class definition + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELOBJECTINVENTORY_H +#define LL_LLPANELOBJECTINVENTORY_H + +#include "llvoinventorylistener.h" +#include "llpanel.h" + +#include "llinventory.h" + +class LLScrollContainer; +class LLFolderView; +class LLFolderViewFolder; +class LLViewerObject; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLPanelObjectInventory +// +// This class represents the panel used to view and control a +// particular task's inventory. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener +{ +public: + // dummy param block for template registration purposes + struct Params : public LLPanel::Params {}; + + LLPanelObjectInventory(const Params&); + virtual ~LLPanelObjectInventory(); + + virtual BOOL postBuild(); + + void doToSelected(const LLSD& userdata); + + void refresh(); + const LLUUID& getTaskUUID() { return mTaskUUID;} + void removeSelectedItem(); + void startRenamingSelectedItem(); + + LLFolderView* getRootFolder() const { return mFolders; } + + virtual void draw(); + virtual void deleteAllChildren(); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); + + static void idle(void* user_data); + +protected: + void reset(); + /*virtual*/ void inventoryChanged(LLViewerObject* object, + InventoryObjectList* inventory, + S32 serial_num, + void* user_data); + void updateInventory(); + void createFolderViews(LLInventoryObject* inventory_root, InventoryObjectList& contents); + void createViewsForCategory(InventoryObjectList* inventory, + LLInventoryObject* parent, + LLFolderViewFolder* folder); + void clearContents(); + +private: + LLScrollContainer* mScroller; + LLFolderView* mFolders; + + LLUUID mTaskUUID; + BOOL mHaveInventory; + BOOL mIsInventoryEmpty; + BOOL mInventoryNeedsUpdate; +}; + +#endif // LL_LLPANELOBJECTINVENTORY_H diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 5197a9bbc3e87f80a2810357b4805f67b5168aea..3cf17fb7f272133156f531d6f51167af2821ca61 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -1,273 +1,244 @@ -/** - * @file LLSidepanelInventory.cpp - * @brief Side Bar "Inventory" panel - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llsidepanelinventory.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llinventorybridge.h" -#include "llinventorypanel.h" -#include "llpanelmaininventory.h" -#include "llsidepanelobjectinfo.h" -#include "lltabcontainer.h" - -static const S32 LANDMARK_FOLDERS_MENU_WIDTH = 250; -static const std::string AGENT_INFO_TYPE = "agent"; -static const std::string CREATE_LANDMARK_INFO_TYPE = "create_landmark"; -static const std::string LANDMARK_INFO_TYPE = "landmark"; -static const std::string REMOTE_PLACE_INFO_TYPE = "remote_place"; -static const std::string TELEPORT_HISTORY_INFO_TYPE = "teleport_history"; - -static LLRegisterPanelClassWrapper<LLSidepanelInventory> t_inventory("sidepanel_inventory"); - -LLSidepanelInventory::LLSidepanelInventory() - : LLPanel(), - mSidepanelObjectInfo(NULL), - mItem(NULL) -{ - - //LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() -} - -LLSidepanelInventory::~LLSidepanelInventory() -{ -} - -BOOL LLSidepanelInventory::postBuild() -{ - mInfoBtn = getChild<LLButton>("info_btn"); - mInfoBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onInfoButtonClicked, this)); - - mShareBtn = getChild<LLButton>("share_btn"); - mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this)); - - mShareBtn = getChild<LLButton>("share_btn"); - mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this)); - - mWearBtn = getChild<LLButton>("wear_btn"); - mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this)); - - mPlayBtn = getChild<LLButton>("play_btn"); - mPlayBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onPlayButtonClicked, this)); - - mTeleportBtn = getChild<LLButton>("teleport_btn"); - mTeleportBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onTeleportButtonClicked, this)); - - mOverflowBtn = getChild<LLButton>("overflow_btn"); - mOverflowBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onOverflowButtonClicked, this)); - - mTabContainer = getChild<LLTabContainer>("Inventory Tabs"); - mSidepanelObjectInfo = getChild<LLSidepanelObjectInfo>("sidepanel_object_info"); - - mPanelMainInventory = getChild<LLPanelMainInventory>("panel_main_inventory"); - mPanelMainInventory->setSelectCallback(boost::bind(&LLSidepanelInventory::onSelectionChange, this, _1, _2)); - - LLButton* back_btn = mSidepanelObjectInfo->getChild<LLButton>("back_btn"); - back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this)); - - return TRUE; -} - -void LLSidepanelInventory::onOpen(const LLSD& key) -{ - if(mSidepanelObjectInfo == NULL || key.size() == 0) - return; - - mItem = NULL; - - LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); - if (!item) - { - return; - } - setItem(item); - toggleObjectInfoPanel(TRUE); -} - -void LLSidepanelInventory::setItem(LLInventoryItem* item) -{ - if (!mSidepanelObjectInfo || !item) - return; - - mItem = item; - - LLAssetType::EType item_type = mItem->getActualType(); - if (item_type == LLAssetType::AT_LINK) - { - mItem = gInventory.getItem(mItem->getLinkedUUID()); - if (mItem.isNull()) - return; - } - - // Check if item is in agent's inventory and he has the permission to modify it. - BOOL is_object_editable = gInventory.isObjectDescendentOf(mItem->getUUID(), gInventory.getRootFolderID()) && - mItem->getPermissions().allowModifyBy(gAgent.getID()); - - mInfoBtn->setEnabled(is_object_editable); - // mSaveBtn->setEnabled(is_object_editable); - - mSidepanelObjectInfo->displayItemInfo(mItem); -} - -void LLSidepanelInventory::onInfoButtonClicked() -{ - LLInventoryItem *item = getSelectedItem(); - if (item) - { - setItem(item); - toggleObjectInfoPanel(TRUE); - } -} - -void LLSidepanelInventory::onShareButtonClicked() -{ -} - -void LLSidepanelInventory::performActionOnSelection(const std::string &action) -{ - LLInventoryPanel *panel = mPanelMainInventory->getActivePanel(); - LLFolderViewItem* current_item = panel->getRootFolder()->getCurSelectedItem(); - if (!current_item) - { - return; - } - current_item->getListener()->performAction(panel->getRootFolder(), panel->getModel(), action); -} - -void LLSidepanelInventory::onWearButtonClicked() -{ - performActionOnSelection("wear"); - performActionOnSelection("attach"); -} - -void LLSidepanelInventory::onPlayButtonClicked() -{ - performActionOnSelection("activate"); -} - -void LLSidepanelInventory::onTeleportButtonClicked() -{ - performActionOnSelection("teleport"); -} - -void LLSidepanelInventory::onOverflowButtonClicked() -{ -} - -void LLSidepanelInventory::onBackButtonClicked() -{ - if (!mSidepanelObjectInfo) - return; - - toggleObjectInfoPanel(FALSE); - - - updateVerbs(); -} - -void LLSidepanelInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) -{ - updateVerbs(); -} - -void LLSidepanelInventory::toggleObjectInfoPanel(BOOL visible) -{ - if (!mSidepanelObjectInfo) - return; - - mSidepanelObjectInfo->setVisible(visible); - mTabContainer->setVisible(!visible); - - if (visible) - { - mSidepanelObjectInfo->reset(); - mSidepanelObjectInfo->setEditMode(FALSE); - - LLRect rect = getRect(); - LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); - mSidepanelObjectInfo->reshape(new_rect.getWidth(),new_rect.getHeight()); - } -} - -void LLSidepanelInventory::updateVerbs() -{ - mInfoBtn->setEnabled(FALSE); - mShareBtn->setEnabled(FALSE); - - mWearBtn->setVisible(FALSE); - mWearBtn->setEnabled(FALSE); - mPlayBtn->setVisible(FALSE); - mPlayBtn->setEnabled(FALSE); - mTeleportBtn->setVisible(FALSE); - mTeleportBtn->setEnabled(FALSE); - - const LLInventoryItem *item = getSelectedItem(); - if (!item) - return; - - mInfoBtn->setEnabled(TRUE); - mShareBtn->setEnabled(TRUE); - - switch(item->getInventoryType()) - { - case LLInventoryType::IT_WEARABLE: - case LLInventoryType::IT_OBJECT: - case LLInventoryType::IT_ATTACHMENT: - mWearBtn->setVisible(TRUE); - mWearBtn->setEnabled(TRUE); - break; - case LLInventoryType::IT_SOUND: - case LLInventoryType::IT_GESTURE: - case LLInventoryType::IT_ANIMATION: - mPlayBtn->setVisible(TRUE); - mPlayBtn->setEnabled(TRUE); - break; - case LLInventoryType::IT_LANDMARK: - mTeleportBtn->setVisible(TRUE); - mTeleportBtn->setEnabled(TRUE); - break; - default: - break; - } -} - -LLInventoryItem *LLSidepanelInventory::getSelectedItem() -{ - LLFolderViewItem* current_item = mPanelMainInventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); - if (!current_item) - { - return NULL; - } - const LLUUID &item_id = current_item->getListener()->getUUID(); - LLInventoryItem *item = gInventory.getItem(item_id); - return item; -} +/** + * @file LLSidepanelInventory.cpp + * @brief Side Bar "Inventory" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsidepanelinventory.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llinventorybridge.h" +#include "llinventorypanel.h" +#include "llpanelmaininventory.h" +#include "llsidepanelobjectinfo.h" +#include "lltabcontainer.h" + +static const S32 LANDMARK_FOLDERS_MENU_WIDTH = 250; +static const std::string AGENT_INFO_TYPE = "agent"; +static const std::string CREATE_LANDMARK_INFO_TYPE = "create_landmark"; +static const std::string LANDMARK_INFO_TYPE = "landmark"; +static const std::string REMOTE_PLACE_INFO_TYPE = "remote_place"; +static const std::string TELEPORT_HISTORY_INFO_TYPE = "teleport_history"; + +static LLRegisterPanelClassWrapper<LLSidepanelInventory> t_inventory("sidepanel_inventory"); + +LLSidepanelInventory::LLSidepanelInventory() + : LLPanel(), + mSidepanelObjectInfo(NULL) +{ + + //LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() +} + +LLSidepanelInventory::~LLSidepanelInventory() +{ +} + +BOOL LLSidepanelInventory::postBuild() +{ + mInfoBtn = getChild<LLButton>("info_btn"); + mInfoBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onInfoButtonClicked, this)); + + mShareBtn = getChild<LLButton>("share_btn"); + mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this)); + + mShareBtn = getChild<LLButton>("share_btn"); + mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this)); + + mWearBtn = getChild<LLButton>("wear_btn"); + mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this)); + + mPlayBtn = getChild<LLButton>("play_btn"); + mPlayBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onPlayButtonClicked, this)); + + mTeleportBtn = getChild<LLButton>("teleport_btn"); + mTeleportBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onTeleportButtonClicked, this)); + + mOverflowBtn = getChild<LLButton>("overflow_btn"); + mOverflowBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onOverflowButtonClicked, this)); + + mTabContainer = getChild<LLTabContainer>("Inventory Tabs"); + mSidepanelObjectInfo = getChild<LLSidepanelObjectInfo>("sidepanel_object_info"); + + mPanelMainInventory = getChild<LLPanelMainInventory>("panel_main_inventory"); + mPanelMainInventory->setSelectCallback(boost::bind(&LLSidepanelInventory::onSelectionChange, this, _1, _2)); + + LLButton* back_btn = mSidepanelObjectInfo->getChild<LLButton>("back_btn"); + back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this)); + + return TRUE; +} + +void LLSidepanelInventory::onOpen(const LLSD& key) +{ + if(key.size() == 0) + return; + + mSidepanelObjectInfo->reset(); + + if (key.has("id")) + { + mSidepanelObjectInfo->setItemID(key["id"].asUUID()); + } + + if (key.has("object")) + { + mSidepanelObjectInfo->setObjectID(key["object"].asUUID()); + } + + toggleObjectInfoPanel(TRUE); +} + +void LLSidepanelInventory::onInfoButtonClicked() +{ + LLInventoryItem *item = getSelectedItem(); + if (item) + { + mSidepanelObjectInfo->reset(); + mSidepanelObjectInfo->setItemID(item->getUUID()); + toggleObjectInfoPanel(TRUE); + } +} + +void LLSidepanelInventory::onShareButtonClicked() +{ +} + +void LLSidepanelInventory::performActionOnSelection(const std::string &action) +{ + LLInventoryPanel *panel = mPanelMainInventory->getActivePanel(); + LLFolderViewItem* current_item = panel->getRootFolder()->getCurSelectedItem(); + if (!current_item) + { + return; + } + current_item->getListener()->performAction(panel->getRootFolder(), panel->getModel(), action); +} + +void LLSidepanelInventory::onWearButtonClicked() +{ + performActionOnSelection("wear"); + performActionOnSelection("attach"); +} + +void LLSidepanelInventory::onPlayButtonClicked() +{ + performActionOnSelection("activate"); +} + +void LLSidepanelInventory::onTeleportButtonClicked() +{ + performActionOnSelection("teleport"); +} + +void LLSidepanelInventory::onOverflowButtonClicked() +{ +} + +void LLSidepanelInventory::onBackButtonClicked() +{ + toggleObjectInfoPanel(FALSE); + updateVerbs(); +} + +void LLSidepanelInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) +{ + updateVerbs(); +} + +void LLSidepanelInventory::toggleObjectInfoPanel(BOOL visible) +{ + mSidepanelObjectInfo->setVisible(visible); + mTabContainer->setVisible(!visible); + + if (visible) + { + mSidepanelObjectInfo->reset(); + mSidepanelObjectInfo->setEditMode(FALSE); + + LLRect rect = getRect(); + LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); + mSidepanelObjectInfo->reshape(new_rect.getWidth(),new_rect.getHeight()); + } +} + +void LLSidepanelInventory::updateVerbs() +{ + mInfoBtn->setEnabled(FALSE); + mShareBtn->setEnabled(FALSE); + + mWearBtn->setVisible(FALSE); + mWearBtn->setEnabled(FALSE); + mPlayBtn->setVisible(FALSE); + mPlayBtn->setEnabled(FALSE); + mTeleportBtn->setVisible(FALSE); + mTeleportBtn->setEnabled(FALSE); + + const LLInventoryItem *item = getSelectedItem(); + if (!item) + return; + + mInfoBtn->setEnabled(TRUE); + mShareBtn->setEnabled(TRUE); + + switch(item->getInventoryType()) + { + case LLInventoryType::IT_WEARABLE: + case LLInventoryType::IT_OBJECT: + case LLInventoryType::IT_ATTACHMENT: + mWearBtn->setVisible(TRUE); + mWearBtn->setEnabled(TRUE); + break; + case LLInventoryType::IT_SOUND: + case LLInventoryType::IT_GESTURE: + case LLInventoryType::IT_ANIMATION: + mPlayBtn->setVisible(TRUE); + mPlayBtn->setEnabled(TRUE); + break; + case LLInventoryType::IT_LANDMARK: + mTeleportBtn->setVisible(TRUE); + mTeleportBtn->setEnabled(TRUE); + break; + default: + break; + } +} + +LLInventoryItem *LLSidepanelInventory::getSelectedItem() +{ + LLFolderViewItem* current_item = mPanelMainInventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); + if (!current_item) + { + return NULL; + } + const LLUUID &item_id = current_item->getListener()->getUUID(); + LLInventoryItem *item = gInventory.getItem(item_id); + return item; +} diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h index 784f5e43b7c700c7f110d0674d3f4359e07cd29f..62eeecc5e2336311b48fd3a40336ed8663115226 100644 --- a/indra/newview/llsidepanelinventory.h +++ b/indra/newview/llsidepanelinventory.h @@ -1,85 +1,80 @@ -/** - * @file LLSidepanelInventory.h - * @brief Side Bar "Inventory" panel - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLSIDEPANELINVENTORY_H -#define LL_LLSIDEPANELINVENTORY_H - -#include "llpanel.h" - -class LLInventoryItem; -class LLSidepanelObjectInfo; -class LLTabContainer; -class LLPanelMainInventory; -class LLFolderViewItem; - -class LLSidepanelInventory : public LLPanel -{ -public: - LLSidepanelInventory(); - virtual ~LLSidepanelInventory(); - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - - void setItem(LLInventoryItem* item); - -protected: - LLInventoryItem *getSelectedItem(); - void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); - void onTabSelected(); - void toggleObjectInfoPanel(BOOL visible); - void updateVerbs(); - void performActionOnSelection(const std::string &action); - - LLTabContainer* mTabContainer; - LLSidepanelObjectInfo* mSidepanelObjectInfo; - LLPanelMainInventory* mPanelMainInventory; - - void onInfoButtonClicked(); - void onShareButtonClicked(); - void onWearButtonClicked(); - void onPlayButtonClicked(); - void onTeleportButtonClicked(); - void onOverflowButtonClicked(); - void onBackButtonClicked(); - - LLButton* mInfoBtn; - LLButton* mShareBtn; - LLButton* mWearBtn; - LLButton* mPlayBtn; - LLButton* mTeleportBtn; - LLButton* mOverflowBtn; - - // Pointer to a item - LLPointer<LLInventoryItem> mItem; -}; - -#endif //LL_LLSIDEPANELINVENTORY_H +/** + * @file LLSidepanelInventory.h + * @brief Side Bar "Inventory" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSIDEPANELINVENTORY_H +#define LL_LLSIDEPANELINVENTORY_H + +#include "llpanel.h" + +class LLInventoryItem; +class LLSidepanelObjectInfo; +class LLTabContainer; +class LLPanelMainInventory; +class LLFolderViewItem; + +class LLSidepanelInventory : public LLPanel +{ +public: + LLSidepanelInventory(); + virtual ~LLSidepanelInventory(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + +protected: + LLInventoryItem *getSelectedItem(); + void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); + void onTabSelected(); + void toggleObjectInfoPanel(BOOL visible); + void updateVerbs(); + void performActionOnSelection(const std::string &action); + + LLTabContainer* mTabContainer; + LLSidepanelObjectInfo* mSidepanelObjectInfo; + LLPanelMainInventory* mPanelMainInventory; + + void onInfoButtonClicked(); + void onShareButtonClicked(); + void onWearButtonClicked(); + void onPlayButtonClicked(); + void onTeleportButtonClicked(); + void onOverflowButtonClicked(); + void onBackButtonClicked(); + + LLButton* mInfoBtn; + LLButton* mShareBtn; + LLButton* mWearBtn; + LLButton* mPlayBtn; + LLButton* mTeleportBtn; + LLButton* mOverflowBtn; +}; + +#endif //LL_LLSIDEPANELINVENTORY_H diff --git a/indra/newview/skins/default/html/da/loading/loading.html b/indra/newview/skins/default/html/da/loading/loading.html index cdad5702b9851f457a48ed564a4533bb7ff5e33a..5f3426eb609306458ed1b8138b2cee9b5b23bee9 100644 --- a/indra/newview/skins/default/html/da/loading/loading.html +++ b/indra/newview/skins/default/html/da/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Indlæser... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Indlæser... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/de/loading/loading.html b/indra/newview/skins/default/html/de/loading/loading.html index 3eddbc24f5e9ae6510ed3cd31e133aa0c2ebd1a3..44a621b2164c6df52c8f42e513a2db51b24397bf 100644 --- a/indra/newview/skins/default/html/de/loading/loading.html +++ b/indra/newview/skins/default/html/de/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Wird geladen... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Wird geladen... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/en-us/loading/loading.html b/indra/newview/skins/default/html/en-us/loading/loading.html index 34e5c84c4d476b1e6a53db45664eef533017aea6..1c62d2f73e0e7ee72773a83e0437bfd62a4c0706 100644 --- a/indra/newview/skins/default/html/en-us/loading/loading.html +++ b/indra/newview/skins/default/html/en-us/loading/loading.html @@ -1,9 +1,9 @@ -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="sl_logo_rotate_black.gif" align="absmiddle"><br/> loading... - </td> - </tr> -</table> -</body> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="sl_logo_rotate_black.gif" align="absmiddle"><br/> loading... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/es/loading/loading.html b/indra/newview/skins/default/html/es/loading/loading.html index f03284ba8ca4d27794bf9217b1ab619ef5cb4c2a..c4260b34c08cea4189b3ea5bed809364ad19d597 100644 --- a/indra/newview/skins/default/html/es/loading/loading.html +++ b/indra/newview/skins/default/html/es/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Cargando... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Cargando... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/fr/loading/loading.html b/indra/newview/skins/default/html/fr/loading/loading.html index 23c0ef03bc4ee5a7a2b316455598fe0d430da1af..b3953448e97ab1b65350fc922deec3b784369e70 100644 --- a/indra/newview/skins/default/html/fr/loading/loading.html +++ b/indra/newview/skins/default/html/fr/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Chargement... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Chargement... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/hu/loading/loading.html b/indra/newview/skins/default/html/hu/loading/loading.html index ade91f76c28b706a7617af45d4b32bcce7f8e96e..ab15a073bae471441748b9112fc1fa3e96903b9f 100644 --- a/indra/newview/skins/default/html/hu/loading/loading.html +++ b/indra/newview/skins/default/html/hu/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Betöltés folyamatban... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Betöltés folyamatban... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/it/loading/loading.html b/indra/newview/skins/default/html/it/loading/loading.html index 0f9af31f6ef880ee8128ad7b19d1d276c594e047..ab37e41f0453bacafde9c57af2ddd15dd57c40f5 100644 --- a/indra/newview/skins/default/html/it/loading/loading.html +++ b/indra/newview/skins/default/html/it/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Attendi... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Attendi... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/ja/loading/loading.html b/indra/newview/skins/default/html/ja/loading/loading.html index 069dc5d12fffac9f361599f97d127db049b12954..35cf74a35f936d5afb971af79a9286cc6f92f6ef 100644 --- a/indra/newview/skins/default/html/ja/loading/loading.html +++ b/indra/newview/skins/default/html/ja/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> ãƒãƒ¼ãƒ‰ä¸... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> ãƒãƒ¼ãƒ‰ä¸... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/nl/loading/loading.html b/indra/newview/skins/default/html/nl/loading/loading.html index 39a8691f3f95053245cd4460d6bc017d3f1faf99..0215bd7e47228e86a3bf8fbb5796a9ef7f8b903b 100644 --- a/indra/newview/skins/default/html/nl/loading/loading.html +++ b/indra/newview/skins/default/html/nl/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Laden... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Laden... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/pl/loading/loading.html b/indra/newview/skins/default/html/pl/loading/loading.html index 515890c2d5cad0801b487db19048d834a61cef85..50f3dfb0c5b18b900f449807c2ee80a463ca1c3e 100644 --- a/indra/newview/skins/default/html/pl/loading/loading.html +++ b/indra/newview/skins/default/html/pl/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Åadowanie... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Åadowanie... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/pt/loading/loading.html b/indra/newview/skins/default/html/pt/loading/loading.html index 635ea62406e12733ed1d6ef4a089b111a53787a7..a83e1123d0f6088510d21df187a13cd9424e1e52 100644 --- a/indra/newview/skins/default/html/pt/loading/loading.html +++ b/indra/newview/skins/default/html/pt/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Carregando... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Carregando... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/ru/loading/loading.html b/indra/newview/skins/default/html/ru/loading/loading.html index dcc0d73c1acfd4e26fce52c806351ccc37ffcf20..892c0b9f7fb045d3c856b40ff7883d6950b702a6 100644 --- a/indra/newview/skins/default/html/ru/loading/loading.html +++ b/indra/newview/skins/default/html/ru/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Загрузка... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Загрузка... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/tr/loading/loading.html b/indra/newview/skins/default/html/tr/loading/loading.html index e7812e7c8e66e913fd9eeb9fcd8ce6bfea6eb548..1ac07bff3403b87bcff4f970c8a7b193a8a44a17 100644 --- a/indra/newview/skins/default/html/tr/loading/loading.html +++ b/indra/newview/skins/default/html/tr/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Yükleniyor... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Yükleniyor... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/uk/loading/loading.html b/indra/newview/skins/default/html/uk/loading/loading.html index 0f67994635083f8e43bcaa2f3ca13d209c55c697..3b5b8679b43d88c8342cba5aa0437eb4bfa91fbe 100644 --- a/indra/newview/skins/default/html/uk/loading/loading.html +++ b/indra/newview/skins/default/html/uk/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Завантаж... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> Завантаж... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/html/zh/loading/loading.html b/indra/newview/skins/default/html/zh/loading/loading.html index 462ea291d9658b33fe6560ac511072b09b952ba3..d1d5d25c927538a41b42ee4eb01c6924bb652d8a 100644 --- a/indra/newview/skins/default/html/zh/loading/loading.html +++ b/indra/newview/skins/default/html/zh/loading/loading.html @@ -1,10 +1,10 @@ -<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> 请ç‰å¾…... - </td> - </tr> -</table> -</body> +<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> +<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> +<table width="100%" height="100%" border="0"> + <tr> + <td align="center" valign="middle" style="font-size:0.8em;"> + <img src="../../en-us/loading/sl_logo_rotate_black.gif" align="absmiddle"><br/> 请ç‰å¾…... + </td> + </tr> +</table> +</body> diff --git a/indra/newview/skins/default/xui/da/panel_edit_profile.xml b/indra/newview/skins/default/xui/da/panel_edit_profile.xml index 74b7c7dd72642afc93cd8e275bf9a503c1430792..b4d0fa20ef12c59d124e1d6cc58d443110d86e18 100644 --- a/indra/newview/skins/default/xui/da/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/da/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Beboer" /> - <string name="AcctTypeTrial" - value="PÃ¥ prøve" /> - <string name="AcctTypeCharterMember" - value="æresmedlem" /> - <string name="AcctTypeEmployee" - value="Linden Lab medarbejder" /> - <string name="PaymentInfoUsed" - value="Betalende medlem" /> - <string name="PaymentInfoOnFile" - value="Registreret betalende" /> - <string name="NoPaymentInfoOnFile" - value="Ingen betalingsinfo" /> - <string name="AgeVerified" - value="Alders-checket" /> - <string name="NotAgeVerified" - value="Ikke alders-checket" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=da - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Optaget autosvar: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Beboer" /> + <string name="AcctTypeTrial" + value="PÃ¥ prøve" /> + <string name="AcctTypeCharterMember" + value="æresmedlem" /> + <string name="AcctTypeEmployee" + value="Linden Lab medarbejder" /> + <string name="PaymentInfoUsed" + value="Betalende medlem" /> + <string name="PaymentInfoOnFile" + value="Registreret betalende" /> + <string name="NoPaymentInfoOnFile" + value="Ingen betalingsinfo" /> + <string name="AgeVerified" + value="Alders-checket" /> + <string name="NotAgeVerified" + value="Ikke alders-checket" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=da + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Partner:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Optaget autosvar: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/de/panel_edit_profile.xml b/indra/newview/skins/default/xui/de/panel_edit_profile.xml index 1f67e0231d06387f251a61f7addf1e6594481aae..3203eacdb5503573ee5f7625d578921db259a6a2 100644 --- a/indra/newview/skins/default/xui/de/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/de/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Einwohner" /> - <string name="AcctTypeTrial" - value="Test" /> - <string name="AcctTypeCharterMember" - value="Charta-Mitglied" /> - <string name="AcctTypeEmployee" - value="Linden Lab-Mitarbeiter" /> - <string name="PaymentInfoUsed" - value="Zahlungsinfo verwendet" /> - <string name="PaymentInfoOnFile" - value="Zahlungsinfo archiviert" /> - <string name="NoPaymentInfoOnFile" - value="Keine Zahlungsinfo archiviert" /> - <string name="AgeVerified" - value="Altersgeprüft" /> - <string name="NotAgeVerified" - value="Nicht altersgeprüft" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=de - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Antwort für Beschäftigt-Modus: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Einwohner" /> + <string name="AcctTypeTrial" + value="Test" /> + <string name="AcctTypeCharterMember" + value="Charta-Mitglied" /> + <string name="AcctTypeEmployee" + value="Linden Lab-Mitarbeiter" /> + <string name="PaymentInfoUsed" + value="Zahlungsinfo verwendet" /> + <string name="PaymentInfoOnFile" + value="Zahlungsinfo archiviert" /> + <string name="NoPaymentInfoOnFile" + value="Keine Zahlungsinfo archiviert" /> + <string name="AgeVerified" + value="Altersgeprüft" /> + <string name="NotAgeVerified" + value="Nicht altersgeprüft" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=de + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Partner:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Antwort für Beschäftigt-Modus: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index 6da4f9e6f3dd0335575d148e54211712421650ae..3e19bdee0fe5ec0da5c491c4f241448b9306babb 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater - legacy_header_height="18" - auto_tile="true" - can_resize="true" - height="563" - layout="topleft" - min_height="150" - min_width="240" - name="Inventory" - help_topic="inventory" - save_rect="true" - save_visibility="true" - single_instance="true" - title="Inventory" - width="467"> - <floater.string - name="Title"> - Inventory - </floater.string> - <floater.string - name="TitleFetching"> - Inventory (Fetching [ITEM_COUNT] Items...) [FILTER] - </floater.string> - <floater.string - name="TitleCompleted"> - Inventory ([ITEM_COUNT] Items) [FILTER] - </floater.string> - <floater.string - name="Fetched"> - Fetched - </floater.string> -<panel - bottom="560" - class="panel_main_inventory" - filename="panel_main_inventory.xml" - follows="all" - layout="topleft" - left="0" - label="Inventory Panel" - name="Inventory Panel" - top="15" - width="467"> -</panel> -</floater> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + auto_tile="true" + can_resize="true" + height="563" + layout="topleft" + min_height="150" + min_width="240" + name="Inventory" + help_topic="inventory" + save_rect="true" + save_visibility="true" + single_instance="true" + title="Inventory" + width="467"> + <floater.string + name="Title"> + Inventory + </floater.string> + <floater.string + name="TitleFetching"> + Inventory (Fetching [ITEM_COUNT] Items...) [FILTER] + </floater.string> + <floater.string + name="TitleCompleted"> + Inventory ([ITEM_COUNT] Items) [FILTER] + </floater.string> + <floater.string + name="Fetched"> + Fetched + </floater.string> +<panel + bottom="560" + class="panel_main_inventory" + filename="panel_main_inventory.xml" + follows="all" + layout="topleft" + left="0" + label="Inventory Panel" + name="Inventory Panel" + top="15" + width="467"> +</panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml index edff1a093a4e827a71a448aec67be9d0f8fa3876..7eaf4fa3ab4c679f517ca0851e717a5d133887a4 100644 --- a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml @@ -1,112 +1,112 @@ -<?xml version="1.0" encoding="utf-8"?> -<menu - create_jump_keys="true" - layout="topleft" - mouse_opaque="false" - visible="false" - name="Gear Menu"> - <menu_item_call - label="View Profile" - layout="topleft" - enabled="true" - name="view_profile"> - <menu_item_call.on_click - function="InspectAvatar.ViewProfile"/> - </menu_item_call> - <menu_item_call - label="Add Friend" - layout="topleft" - name="add_friend"> - <menu_item_call.on_click - function="InspectAvatar.AddFriend"/> - </menu_item_call> - <menu_item_call - label="IM" - layout="topleft" - name="im"> - <menu_item_call.on_click - function="InspectAvatar.IM"/> - </menu_item_call> - <menu_item_call - label="Call" - layout="topleft" - enabled="true" - name="call"> - </menu_item_call> - <menu_item_call - label="Teleport" - layout="topleft" - name="teleport"> - <menu_item_call.on_click - function="InspectAvatar.Teleport"/> - </menu_item_call> - <menu_item_call - label="Invite to Group" - layout="topleft" - name="invite_to_group"> - <menu_item_call.on_click - function="InspectAvatar.InviteToGroup"/> - </menu_item_call> - <menu_item_separator layout="topleft" /> - <menu_item_call - label="Block" - layout="topleft" - name="block"> - <menu_item_call.on_click - function="InspectAvatar.Block"/> - </menu_item_call> - <menu_item_call - label="Report" - layout="topleft" - name="report"> - <menu_item_call.on_click - function="InspectAvatar.Report"/> - </menu_item_call> - <menu_item_call - label="Freeze" - name="freeze"> - <menu_item_call.on_click - function="InspectAvatar.Freeze"/> - <menu_item_call.on_visible - function="IsGodCustomerService"/> - </menu_item_call> - <menu_item_call - label="Eject" - name="eject"> - <menu_item_call.on_click - function="InspectAvatar.Eject"/> - <menu_item_call.on_visible - function="IsGodCustomerService"/> - </menu_item_call> - <menu_item_call - label="Debug" - name="debug"> - <menu_item_call.on_click - function="InspectAvatar.Debug"/> - <menu_item_call.on_visible - function="IsGodCustomerService"/> - </menu_item_call> - <menu_item_call - label="Find On Map" - layout="topleft" - name="find_on_map"> - <menu_item_call.on_click - function="InspectAvatar.FindOnMap"/> - <menu_item_call.on_visible - function="InspectAvatar.VisibleFindOnMap"/> - </menu_item_call> - <menu_item_call - label="Zoom In" - layout="topleft" - name="zoom_in"> - <menu_item_call.on_click - function="InspectAvatar.ZoomIn"/> - </menu_item_call> - <menu_item_call - label="Pay" - layout="topleft" - name="pay"> - <menu_item_call.on_click - function="InspectAvatar.Pay"/> - </menu_item_call> +<?xml version="1.0" encoding="utf-8"?> +<menu + create_jump_keys="true" + layout="topleft" + mouse_opaque="false" + visible="false" + name="Gear Menu"> + <menu_item_call + label="View Profile" + layout="topleft" + enabled="true" + name="view_profile"> + <menu_item_call.on_click + function="InspectAvatar.ViewProfile"/> + </menu_item_call> + <menu_item_call + label="Add Friend" + layout="topleft" + name="add_friend"> + <menu_item_call.on_click + function="InspectAvatar.AddFriend"/> + </menu_item_call> + <menu_item_call + label="IM" + layout="topleft" + name="im"> + <menu_item_call.on_click + function="InspectAvatar.IM"/> + </menu_item_call> + <menu_item_call + label="Call" + layout="topleft" + enabled="true" + name="call"> + </menu_item_call> + <menu_item_call + label="Teleport" + layout="topleft" + name="teleport"> + <menu_item_call.on_click + function="InspectAvatar.Teleport"/> + </menu_item_call> + <menu_item_call + label="Invite to Group" + layout="topleft" + name="invite_to_group"> + <menu_item_call.on_click + function="InspectAvatar.InviteToGroup"/> + </menu_item_call> + <menu_item_separator layout="topleft" /> + <menu_item_call + label="Block" + layout="topleft" + name="block"> + <menu_item_call.on_click + function="InspectAvatar.Block"/> + </menu_item_call> + <menu_item_call + label="Report" + layout="topleft" + name="report"> + <menu_item_call.on_click + function="InspectAvatar.Report"/> + </menu_item_call> + <menu_item_call + label="Freeze" + name="freeze"> + <menu_item_call.on_click + function="InspectAvatar.Freeze"/> + <menu_item_call.on_visible + function="IsGodCustomerService"/> + </menu_item_call> + <menu_item_call + label="Eject" + name="eject"> + <menu_item_call.on_click + function="InspectAvatar.Eject"/> + <menu_item_call.on_visible + function="IsGodCustomerService"/> + </menu_item_call> + <menu_item_call + label="Debug" + name="debug"> + <menu_item_call.on_click + function="InspectAvatar.Debug"/> + <menu_item_call.on_visible + function="IsGodCustomerService"/> + </menu_item_call> + <menu_item_call + label="Find On Map" + layout="topleft" + name="find_on_map"> + <menu_item_call.on_click + function="InspectAvatar.FindOnMap"/> + <menu_item_call.on_visible + function="InspectAvatar.VisibleFindOnMap"/> + </menu_item_call> + <menu_item_call + label="Zoom In" + layout="topleft" + name="zoom_in"> + <menu_item_call.on_click + function="InspectAvatar.ZoomIn"/> + </menu_item_call> + <menu_item_call + label="Pay" + layout="topleft" + name="pay"> + <menu_item_call.on_click + function="InspectAvatar.Pay"/> + </menu_item_call> </menu> \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml index 240822e5cab8c200505518ae79c13f316cf5e5a3..19c2bf34969fc6557b2acf66c4baaece4d59dc8f 100644 --- a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml @@ -1,53 +1,53 @@ -<?xml version="1.0" encoding="utf-8"?> -<menu - create_jump_keys="true" - layout="topleft" - mouse_opaque="false" - visible="false" - name="Gear Menu"> - <menu_item_call - label="Stand Up" - layout="topleft" - enabled="true" - name="stand_up"> - <menu_item_call.on_click - function="Self.StandUp" - parameter="" /> - <menu_item_call.on_visible - function="Self.VisibleStandUp" /> - </menu_item_call> - <menu_item_call - label="My Appearance" - layout="topleft" - name="my_appearance"> - <menu_item_call.on_click - function="ShowFloater" - parameter="appearance" /> - <menu_item_call.on_enable - function="Edit.EnableCustomizeAvatar" /> - </menu_item_call> - <menu_item_call - label="My Profile" - layout="topleft" - enabled="true" - name="my_profile"> - <menu_item_call.on_click - function="ShowAgentProfile" - parameter="agent" /> - </menu_item_call> - <menu_item_call - label="My Friends" - layout="topleft" - name="my_friends"> - <menu_item_call.on_click - function="Self.Friends" - parameter="" /> - </menu_item_call> - <menu_item_call - label="My Groups" - layout="topleft" - name="my_groups"> - <menu_item_call.on_click - function="Self.Groups" /> - </menu_item_call> +<?xml version="1.0" encoding="utf-8"?> +<menu + create_jump_keys="true" + layout="topleft" + mouse_opaque="false" + visible="false" + name="Gear Menu"> + <menu_item_call + label="Stand Up" + layout="topleft" + enabled="true" + name="stand_up"> + <menu_item_call.on_click + function="Self.StandUp" + parameter="" /> + <menu_item_call.on_visible + function="Self.VisibleStandUp" /> + </menu_item_call> + <menu_item_call + label="My Appearance" + layout="topleft" + name="my_appearance"> + <menu_item_call.on_click + function="ShowFloater" + parameter="appearance" /> + <menu_item_call.on_enable + function="Edit.EnableCustomizeAvatar" /> + </menu_item_call> + <menu_item_call + label="My Profile" + layout="topleft" + enabled="true" + name="my_profile"> + <menu_item_call.on_click + function="ShowAgentProfile" + parameter="agent" /> + </menu_item_call> + <menu_item_call + label="My Friends" + layout="topleft" + name="my_friends"> + <menu_item_call.on_click + function="Self.Friends" + parameter="" /> + </menu_item_call> + <menu_item_call + label="My Groups" + layout="topleft" + name="my_groups"> + <menu_item_call.on_click + function="Self.Groups" /> + </menu_item_call> </menu> \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index c50278ff8cc60fe7e9e4f538a53f5b48d6da7396..9a3fdcc327b103750fc94a687ea8650ef829a116 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -1,415 +1,415 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel - background_visible="true" - follows="all" - height="400" - label="Things" - layout="topleft" - min_height="350" - min_width="240" - name="inventory panel" - width="330"> - <panel.string - name="Title"> - Things - </panel.string> - <filter_editor - text_pad_left="12" - follows="left|top|right" - font="SanSerif" - height="20" - label="Filter" - layout="topleft" - left="15" - name="inventory search editor" - top="34" - width="300" /> - <tab_container - follows="left|top|right|bottom" - height="300" - layout="topleft" - left_delta="-4" - name="inventory filter tabs" - tab_position="top" - top_pad="4" - width="305"> - <inventory_panel - follows="left|top|right|bottom" - height="295" - label="All Items" - layout="topleft" - left="1" - name="All Items" - top="16" - width="290" /> - <inventory_panel - follows="left|top|right|bottom" - height="295" - label="Recent Items" - layout="topleft" - left_delta="0" - name="Recent Items" - top_delta="0" - width="290" /> - </tab_container> - <menu_bar - bg_visible="false" - follows="left|top|right" - height="18" - layout="topleft" - left_delta="0" - mouse_opaque="false" - name="Inventory Menu" - top_delta="-45" - width="290"> - <menu - height="101" - label="File" - layout="topleft" - left="0" - mouse_opaque="false" - name="File" - tear_off="true" - top="-117" - width="128"> - <menu_item_call - label="Open" - layout="topleft" - name="Open"> - <menu_item_call.on_click - function="Inventory.DoToSelected" - parameter="open" /> - </menu_item_call> - <menu - create_jump_keys="true" - label="Upload" - layout="topleft" - name="upload" - tear_off="true"> - <menu_item_call - label="Image (L$[COST])..." - layout="topleft" - name="Upload Image" - shortcut="control|U"> - <menu_item_call.on_click - function="File.UploadImage" - parameter="" /> - <menu_item_call.on_enable - function="File.EnableUpload" /> - </menu_item_call> - <menu_item_call - label="Sound (L$[COST])..." - layout="topleft" - name="Upload Sound"> - <menu_item_call.on_click - function="File.UploadSound" - parameter="" /> - <menu_item_call.on_enable - function="File.EnableUpload" /> - </menu_item_call> - <menu_item_call - label="Animation (L$[COST])..." - layout="topleft" - name="Upload Animation"> - <menu_item_call.on_click - function="File.UploadAnim" - parameter="" /> - <menu_item_call.on_enable - function="File.EnableUpload" /> - </menu_item_call> - <menu_item_call - label="Bulk (L$[COST] per file)..." - layout="topleft" - name="Bulk Upload"> - <menu_item_call.on_click - function="File.UploadBulk" - parameter="" /> - </menu_item_call> - <menu_item_separator - layout="topleft" /> - </menu> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="New Window" - layout="topleft" - name="New Window"> - <menu_item_call.on_click - function="Inventory.NewWindow" /> - </menu_item_call> - <menu_item_separator - layout="topleft" - name="separator2" /> - <menu_item_call - label="Show Filters" - layout="topleft" - name="Show Filters"> - <menu_item_call.on_click - function="Inventory.ShowFilters" /> - </menu_item_call> - <menu_item_call - label="Reset Filters" - layout="topleft" - name="Reset Current"> - <menu_item_call.on_click - function="Inventory.ResetFilter" /> - </menu_item_call> - <menu_item_call - label="Close All Folders" - layout="topleft" - name="Close All Folders"> - <menu_item_call.on_click - function="Inventory.CloseAllFolders" /> - </menu_item_call> - <menu_item_separator - layout="topleft" - name="separator3" /> - <menu_item_call - label="Empty Trash" - layout="topleft" - name="Empty Trash"> - <menu_item_call.on_click - function="Inventory.EmptyTrash" /> - </menu_item_call> - <menu_item_call - label="Empty Lost And Found" - layout="topleft" - name="Empty Lost And Found"> - <menu_item_call.on_click - function="Inventory.EmptyLostAndFound" /> - </menu_item_call> - </menu> - <menu - height="121" - label="Create" - layout="topleft" - left="0" - mouse_opaque="false" - name="Create" - tear_off="true" - top="-201" - width="121"> - <menu_item_call - label="New Folder" - layout="topleft" - name="New Folder"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="category" /> - </menu_item_call> - <menu_item_call - label="New Script" - layout="topleft" - name="New Script"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="lsl" /> - </menu_item_call> - <menu_item_call - label="New Note" - layout="topleft" - name="New Note"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="notecard" /> - </menu_item_call> - <menu_item_call - label="New Gesture" - layout="topleft" - name="New Gesture"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="gesture" /> - </menu_item_call> - <menu - height="175" - label="New Clothes" - layout="topleft" - left_delta="0" - mouse_opaque="false" - name="New Clothes" - top_pad="514" - width="125"> - <menu_item_call - label="New Shirt" - layout="topleft" - name="New Shirt"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="shirt" /> - </menu_item_call> - <menu_item_call - label="New Pants" - layout="topleft" - name="New Pants"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="pants" /> - </menu_item_call> - <menu_item_call - label="New Shoes" - layout="topleft" - name="New Shoes"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="shoes" /> - </menu_item_call> - <menu_item_call - label="New Socks" - layout="topleft" - name="New Socks"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="socks" /> - </menu_item_call> - <menu_item_call - label="New Jacket" - layout="topleft" - name="New Jacket"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="jacket" /> - </menu_item_call> - <menu_item_call - label="New Skirt" - layout="topleft" - name="New Skirt"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="skirt" /> - </menu_item_call> - <menu_item_call - label="New Gloves" - layout="topleft" - name="New Gloves"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="gloves" /> - </menu_item_call> - <menu_item_call - label="New Undershirt" - layout="topleft" - name="New Undershirt"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="undershirt" /> - </menu_item_call> - <menu_item_call - label="New Underpants" - layout="topleft" - name="New Underpants"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="underpants" /> - </menu_item_call> - <menu_item_call - label="New Alpha" - layout="topleft" - name="New Alpha"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="alpha" /> - </menu_item_call> - <menu_item_call - label="New Tattoo" - layout="topleft" - name="New Tattoo"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="tattoo" /> - </menu_item_call> - </menu> - <menu - height="85" - label="New Body Parts" - layout="topleft" - left_delta="0" - mouse_opaque="false" - name="New Body Parts" - top_pad="514" - width="118"> - <menu_item_call - label="New Shape" - layout="topleft" - name="New Shape"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="shape" /> - </menu_item_call> - <menu_item_call - label="New Skin" - layout="topleft" - name="New Skin"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="skin" /> - </menu_item_call> - <menu_item_call - label="New Hair" - layout="topleft" - name="New Hair"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="hair" /> - </menu_item_call> - <menu_item_call - label="New Eyes" - layout="topleft" - name="New Eyes"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="eyes" /> - </menu_item_call> - </menu> - </menu> - <menu - height="49" - label="Sort" - layout="topleft" - left="0" - mouse_opaque="false" - name="Sort" - tear_off="true" - top="-113" - width="118"> - <menu_item_check - control_name="Inventory.SortByName" - label="By Name" - layout="topleft" - name="By Name"> - <menu_item_check.on_click - function="Inventory.SetSortBy" - parameter="name" /> - </menu_item_check> - <menu_item_check - control_name="Inventory.SortByDate" - label="By Date" - layout="topleft" - name="By Date"> - <menu_item_check.on_click - function="Inventory.SetSortBy" - parameter="date" /> - </menu_item_check> - <menu_item_separator - layout="topleft" /> - <menu_item_check - control_name="Inventory.FoldersAlwaysByName" - label="Folders Always By Name" - layout="topleft" - name="Folders Always By Name"> - <menu_item_check.on_click - function="Inventory.SetSortBy" - parameter="foldersalwaysbyname" /> - </menu_item_check> - <menu_item_check - control_name="Inventory.SystemFoldersToTop" - label="System Folders To Top" - layout="topleft" - name="System Folders To Top"> - <menu_item_check.on_click - function="Inventory.SetSortBy" - parameter="systemfolderstotop" /> - </menu_item_check> - </menu> - </menu_bar> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + background_visible="true" + follows="all" + height="400" + label="Things" + layout="topleft" + min_height="350" + min_width="240" + name="inventory panel" + width="330"> + <panel.string + name="Title"> + Things + </panel.string> + <filter_editor + text_pad_left="12" + follows="left|top|right" + font="SanSerif" + height="20" + label="Filter" + layout="topleft" + left="15" + name="inventory search editor" + top="34" + width="300" /> + <tab_container + follows="left|top|right|bottom" + height="300" + layout="topleft" + left_delta="-4" + name="inventory filter tabs" + tab_position="top" + top_pad="4" + width="305"> + <inventory_panel + follows="left|top|right|bottom" + height="295" + label="All Items" + layout="topleft" + left="1" + name="All Items" + top="16" + width="290" /> + <inventory_panel + follows="left|top|right|bottom" + height="295" + label="Recent Items" + layout="topleft" + left_delta="0" + name="Recent Items" + top_delta="0" + width="290" /> + </tab_container> + <menu_bar + bg_visible="false" + follows="left|top|right" + height="18" + layout="topleft" + left_delta="0" + mouse_opaque="false" + name="Inventory Menu" + top_delta="-45" + width="290"> + <menu + height="101" + label="File" + layout="topleft" + left="0" + mouse_opaque="false" + name="File" + tear_off="true" + top="-117" + width="128"> + <menu_item_call + label="Open" + layout="topleft" + name="Open"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="open" /> + </menu_item_call> + <menu + create_jump_keys="true" + label="Upload" + layout="topleft" + name="upload" + tear_off="true"> + <menu_item_call + label="Image (L$[COST])..." + layout="topleft" + name="Upload Image" + shortcut="control|U"> + <menu_item_call.on_click + function="File.UploadImage" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call + label="Sound (L$[COST])..." + layout="topleft" + name="Upload Sound"> + <menu_item_call.on_click + function="File.UploadSound" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call + label="Animation (L$[COST])..." + layout="topleft" + name="Upload Animation"> + <menu_item_call.on_click + function="File.UploadAnim" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUpload" /> + </menu_item_call> + <menu_item_call + label="Bulk (L$[COST] per file)..." + layout="topleft" + name="Bulk Upload"> + <menu_item_call.on_click + function="File.UploadBulk" + parameter="" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + </menu> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="New Window" + layout="topleft" + name="New Window"> + <menu_item_call.on_click + function="Inventory.NewWindow" /> + </menu_item_call> + <menu_item_separator + layout="topleft" + name="separator2" /> + <menu_item_call + label="Show Filters" + layout="topleft" + name="Show Filters"> + <menu_item_call.on_click + function="Inventory.ShowFilters" /> + </menu_item_call> + <menu_item_call + label="Reset Filters" + layout="topleft" + name="Reset Current"> + <menu_item_call.on_click + function="Inventory.ResetFilter" /> + </menu_item_call> + <menu_item_call + label="Close All Folders" + layout="topleft" + name="Close All Folders"> + <menu_item_call.on_click + function="Inventory.CloseAllFolders" /> + </menu_item_call> + <menu_item_separator + layout="topleft" + name="separator3" /> + <menu_item_call + label="Empty Trash" + layout="topleft" + name="Empty Trash"> + <menu_item_call.on_click + function="Inventory.EmptyTrash" /> + </menu_item_call> + <menu_item_call + label="Empty Lost And Found" + layout="topleft" + name="Empty Lost And Found"> + <menu_item_call.on_click + function="Inventory.EmptyLostAndFound" /> + </menu_item_call> + </menu> + <menu + height="121" + label="Create" + layout="topleft" + left="0" + mouse_opaque="false" + name="Create" + tear_off="true" + top="-201" + width="121"> + <menu_item_call + label="New Folder" + layout="topleft" + name="New Folder"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="category" /> + </menu_item_call> + <menu_item_call + label="New Script" + layout="topleft" + name="New Script"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="lsl" /> + </menu_item_call> + <menu_item_call + label="New Note" + layout="topleft" + name="New Note"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="notecard" /> + </menu_item_call> + <menu_item_call + label="New Gesture" + layout="topleft" + name="New Gesture"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="gesture" /> + </menu_item_call> + <menu + height="175" + label="New Clothes" + layout="topleft" + left_delta="0" + mouse_opaque="false" + name="New Clothes" + top_pad="514" + width="125"> + <menu_item_call + label="New Shirt" + layout="topleft" + name="New Shirt"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="shirt" /> + </menu_item_call> + <menu_item_call + label="New Pants" + layout="topleft" + name="New Pants"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="pants" /> + </menu_item_call> + <menu_item_call + label="New Shoes" + layout="topleft" + name="New Shoes"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="shoes" /> + </menu_item_call> + <menu_item_call + label="New Socks" + layout="topleft" + name="New Socks"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="socks" /> + </menu_item_call> + <menu_item_call + label="New Jacket" + layout="topleft" + name="New Jacket"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="jacket" /> + </menu_item_call> + <menu_item_call + label="New Skirt" + layout="topleft" + name="New Skirt"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="skirt" /> + </menu_item_call> + <menu_item_call + label="New Gloves" + layout="topleft" + name="New Gloves"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="gloves" /> + </menu_item_call> + <menu_item_call + label="New Undershirt" + layout="topleft" + name="New Undershirt"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="undershirt" /> + </menu_item_call> + <menu_item_call + label="New Underpants" + layout="topleft" + name="New Underpants"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="underpants" /> + </menu_item_call> + <menu_item_call + label="New Alpha" + layout="topleft" + name="New Alpha"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="alpha" /> + </menu_item_call> + <menu_item_call + label="New Tattoo" + layout="topleft" + name="New Tattoo"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="tattoo" /> + </menu_item_call> + </menu> + <menu + height="85" + label="New Body Parts" + layout="topleft" + left_delta="0" + mouse_opaque="false" + name="New Body Parts" + top_pad="514" + width="118"> + <menu_item_call + label="New Shape" + layout="topleft" + name="New Shape"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="shape" /> + </menu_item_call> + <menu_item_call + label="New Skin" + layout="topleft" + name="New Skin"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="skin" /> + </menu_item_call> + <menu_item_call + label="New Hair" + layout="topleft" + name="New Hair"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="hair" /> + </menu_item_call> + <menu_item_call + label="New Eyes" + layout="topleft" + name="New Eyes"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="eyes" /> + </menu_item_call> + </menu> + </menu> + <menu + height="49" + label="Sort" + layout="topleft" + left="0" + mouse_opaque="false" + name="Sort" + tear_off="true" + top="-113" + width="118"> + <menu_item_check + control_name="Inventory.SortByName" + label="By Name" + layout="topleft" + name="By Name"> + <menu_item_check.on_click + function="Inventory.SetSortBy" + parameter="name" /> + </menu_item_check> + <menu_item_check + control_name="Inventory.SortByDate" + label="By Date" + layout="topleft" + name="By Date"> + <menu_item_check.on_click + function="Inventory.SetSortBy" + parameter="date" /> + </menu_item_check> + <menu_item_separator + layout="topleft" /> + <menu_item_check + control_name="Inventory.FoldersAlwaysByName" + label="Folders Always By Name" + layout="topleft" + name="Folders Always By Name"> + <menu_item_check.on_click + function="Inventory.SetSortBy" + parameter="foldersalwaysbyname" /> + </menu_item_check> + <menu_item_check + control_name="Inventory.SystemFoldersToTop" + label="System Folders To Top" + layout="topleft" + name="System Folders To Top"> + <menu_item_check.on_click + function="Inventory.SetSortBy" + parameter="systemfolderstotop" /> + </menu_item_check> + </menu> + </menu_bar> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml index 777d5b48fe86db7bf49500232cf8fc197a6caf0c..3582de1c711f0c4f8f594d7f3a855a7f26427ca7 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml @@ -1,150 +1,150 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<!-- Side tray cannot show background because it is always - partially on screen to hold tab buttons. --> -<side_tray - name="sidebar" - background_visible="false" - mouse_opaque="true" - width="333" - collapsed="true" -> - <!-- Individual tabs must show background to have seemless - appearance up to tray panel header word like "Home". - Embedded panels are inset by a pixel and so their - backgrounds will not block the world fully. --> - <sidetray_tab - name="sidebar_home" - help_topic="sidebar_home" - tab_title="Home" - description="Home." - image="TabIcon_Open_Off" - image_selected="TabIcon_Close_Off" - mouse_opaque="false" - background_visible="true" - > - <panel - name="panel_home" - filename="panel_sidetray_home_tab.xml" - label="home" - /> - </sidetray_tab> - - <sidetray_tab - name="sidebar_people" - help_topic="sidebar_people" - tab_title="People" - description="Find your friends, contacts and people nearby." - image="TabIcon_People_Off" - image_selected="TabIcon_People_Selected" - mouse_opaque="false" - background_visible="true" - > - <panel_container - name="panel_container" - width="333" - > - <panel - class="panel_people" - name="panel_people" - filename="panel_people.xml" - /> - <panel - class="panel_profile_view" - name="panel_profile_view" - filename="panel_profile_view.xml" - /> - <panel - class="panel_group_info_sidetray" - name="panel_group_info_sidetray" - filename="panel_group_info_sidetray.xml" - label="Group Info" - font="SansSerifBold" - /> - <panel - class="panel_block_list_sidetray" - name="panel_block_list_sidetray" - filename="panel_block_list_sidetray.xml" - label="Blocked Residents & Objects" - font="SansSerifBold" - /> - - </panel_container> - </sidetray_tab> - - <sidetray_tab - name="sidebar_places" - help_topic="sidebar_places" - tab_title="Places" - label="Places" - description="Find places to go and places you've visited before." - image="TabIcon_Places_Off" - image_selected="TabIcon_Places_Selected" - mouse_opaque="false" - background_visible="true" - > - <panel - class="panel_places" - name="panel_places" - filename="panel_places.xml" - label="Places" - font="SansSerifBold" - /> - </sidetray_tab> - - <sidetray_tab - name="sidebar_me" - help_topic="sidebar_me" - tab_title="Me" - description="Edit your public profile and Picks." - image="TabIcon_Me_Off" - image_selected="TabIcon_Me_Selected" - mouse_opaque="false" - background_visible="true" - > - <panel - class="panel_me_profile_view" - name="panel_me_profile" - filename="panel_me_profile.xml" - label="Me" - /> - </sidetray_tab> - - <sidetray_tab - name="sidebar_appearance" - help_topic="sidebar_appearance" - tab_title="Appearance" - description="Change your appearance and current look." - image="TabIcon_Appearance_Off" - image_selected="TabIcon_Appearance_Selected" - mouse_opaque="false" - background_visible="true" - > - <panel - class="panel_appearance" - name="panel_appearance" - filename="panel_appearance.xml" - label="Edit Appearance" - font="SansSerifBold" - /> - </sidetray_tab> - - <sidetray_tab - name="sidebar_inventory" - help_topic="sidebar_inventory" - tab_title="Inventory" - description="Browse your inventory." - image="TabIcon_Inventory_Off" - image_selected="TabIcon_Inventory_Selected" - mouse_opaque="false" - background_visible="true" - > - <panel - class="sidepanel_inventory" - name="sidepanel_inventory" - filename="sidepanel_inventory.xml" - label="Edit Inventory" - font="SansSerifBold" - /> - </sidetray_tab> - -</side_tray> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<!-- Side tray cannot show background because it is always + partially on screen to hold tab buttons. --> +<side_tray + name="sidebar" + background_visible="false" + mouse_opaque="true" + width="333" + collapsed="true" +> + <!-- Individual tabs must show background to have seemless + appearance up to tray panel header word like "Home". + Embedded panels are inset by a pixel and so their + backgrounds will not block the world fully. --> + <sidetray_tab + name="sidebar_home" + help_topic="sidebar_home" + tab_title="Home" + description="Home." + image="TabIcon_Open_Off" + image_selected="TabIcon_Close_Off" + mouse_opaque="false" + background_visible="true" + > + <panel + name="panel_home" + filename="panel_sidetray_home_tab.xml" + label="home" + /> + </sidetray_tab> + + <sidetray_tab + name="sidebar_people" + help_topic="sidebar_people" + tab_title="People" + description="Find your friends, contacts and people nearby." + image="TabIcon_People_Off" + image_selected="TabIcon_People_Selected" + mouse_opaque="false" + background_visible="true" + > + <panel_container + name="panel_container" + width="333" + > + <panel + class="panel_people" + name="panel_people" + filename="panel_people.xml" + /> + <panel + class="panel_profile_view" + name="panel_profile_view" + filename="panel_profile_view.xml" + /> + <panel + class="panel_group_info_sidetray" + name="panel_group_info_sidetray" + filename="panel_group_info_sidetray.xml" + label="Group Info" + font="SansSerifBold" + /> + <panel + class="panel_block_list_sidetray" + name="panel_block_list_sidetray" + filename="panel_block_list_sidetray.xml" + label="Blocked Residents & Objects" + font="SansSerifBold" + /> + + </panel_container> + </sidetray_tab> + + <sidetray_tab + name="sidebar_places" + help_topic="sidebar_places" + tab_title="Places" + label="Places" + description="Find places to go and places you've visited before." + image="TabIcon_Places_Off" + image_selected="TabIcon_Places_Selected" + mouse_opaque="false" + background_visible="true" + > + <panel + class="panel_places" + name="panel_places" + filename="panel_places.xml" + label="Places" + font="SansSerifBold" + /> + </sidetray_tab> + + <sidetray_tab + name="sidebar_me" + help_topic="sidebar_me" + tab_title="Me" + description="Edit your public profile and Picks." + image="TabIcon_Me_Off" + image_selected="TabIcon_Me_Selected" + mouse_opaque="false" + background_visible="true" + > + <panel + class="panel_me_profile_view" + name="panel_me_profile" + filename="panel_me_profile.xml" + label="Me" + /> + </sidetray_tab> + + <sidetray_tab + name="sidebar_appearance" + help_topic="sidebar_appearance" + tab_title="Appearance" + description="Change your appearance and current look." + image="TabIcon_Appearance_Off" + image_selected="TabIcon_Appearance_Selected" + mouse_opaque="false" + background_visible="true" + > + <panel + class="panel_appearance" + name="panel_appearance" + filename="panel_appearance.xml" + label="Edit Appearance" + font="SansSerifBold" + /> + </sidetray_tab> + + <sidetray_tab + name="sidebar_inventory" + help_topic="sidebar_inventory" + tab_title="Inventory" + description="Browse your inventory." + image="TabIcon_Inventory_Off" + image_selected="TabIcon_Inventory_Selected" + mouse_opaque="false" + background_visible="true" + > + <panel + class="sidepanel_inventory" + name="sidepanel_inventory" + filename="sidepanel_inventory.xml" + label="Edit Inventory" + font="SansSerifBold" + /> + </sidetray_tab> + +</side_tray> diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml index 79a1cc945d08438528b194ae2d98fc18f9b04b66..d0c3cdfafcf1289f0d40d4d1e0f9a4f451a262f9 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml @@ -1,122 +1,122 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel - background_visible="true" - follows="all" - height="400" - label="Things" - layout="topleft" - min_height="350" - min_width="240" - name="objects panel" - width="333"> - <tab_container - follows="all" - height="390" - layout="topleft" - left="9" - name="Inventory Tabs" - tab_position="top" - top="0" - width="313" - tab_height="0" - visible="true"> - <panel - class="panel_main_inventory" - filename="panel_main_inventory.xml" - follows="all" - layout="topleft" - left="0" - name="panel_main_inventory" - top="15" - label="" - height="330" - width="467"> - <panel - height="25" - layout="bottomright" - left="0" - help_topic="objects_button_tab" - name="button_panel" - bottom="0" - width="313"> - <button - enabled="true" - follows="bottom|left" - font="SansSerifSmallBold" - height="25" - label="Info" - layout="topleft" - left="0" - name="info_btn" - top="0" - width="60" /> - <button - enabled="true" - follows="bottom|left" - font="SansSerifSmallBold" - height="25" - label="Share" - layout="topleft" - left_pad="5" - name="share_btn" - top="0" - width="60" /> - <button - enabled="false" - follows="bottom|left" - font="SansSerifSmallBold" - height="25" - label="Wear" - layout="topleft" - left="130" - name="wear_btn" - top="0" - width="60" /> - <button - enabled="false" - follows="bottom|left" - font="SansSerifSmallBold" - height="25" - label="Play" - layout="topleft" - name="play_btn" - left="130" - top="0" - width="50" /> - <button - enabled="false" - follows="bottom|left" - font="SansSerifSmallBold" - height="25" - label="Teleport" - layout="topleft" - left="130" - name="teleport_btn" - top="0" - width="77" /> - <button - follows="bottom|right" - font="SansSerifSmallBold" - height="25" - label="v" - layout="topleft" - name="overflow_btn" - right="-10" - top="0" - width="30" /> - </panel> - </panel> - </tab_container> - - <panel - class="sidepanel_object_info" - filename="sidepanel_object_info.xml" - follows="all" - height="360" - layout="topleft" - left="0" - help_topic="objects_info_tab" - name="sidepanel_object_info" - top="30" - visible="false" /> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + background_visible="true" + follows="all" + height="400" + label="Things" + layout="topleft" + min_height="350" + min_width="240" + name="objects panel" + width="333"> + <tab_container + follows="all" + height="390" + layout="topleft" + left="9" + name="Inventory Tabs" + tab_position="top" + top="0" + width="313" + tab_height="0" + visible="true"> + <panel + class="panel_main_inventory" + filename="panel_main_inventory.xml" + follows="all" + layout="topleft" + left="0" + name="panel_main_inventory" + top="15" + label="" + height="330" + width="467"> + <panel + height="25" + layout="bottomright" + left="0" + help_topic="objects_button_tab" + name="button_panel" + bottom="0" + width="313"> + <button + enabled="true" + follows="bottom|left" + font="SansSerifSmallBold" + height="25" + label="Info" + layout="topleft" + left="0" + name="info_btn" + top="0" + width="60" /> + <button + enabled="true" + follows="bottom|left" + font="SansSerifSmallBold" + height="25" + label="Share" + layout="topleft" + left_pad="5" + name="share_btn" + top="0" + width="60" /> + <button + enabled="false" + follows="bottom|left" + font="SansSerifSmallBold" + height="25" + label="Wear" + layout="topleft" + left="130" + name="wear_btn" + top="0" + width="60" /> + <button + enabled="false" + follows="bottom|left" + font="SansSerifSmallBold" + height="25" + label="Play" + layout="topleft" + name="play_btn" + left="130" + top="0" + width="50" /> + <button + enabled="false" + follows="bottom|left" + font="SansSerifSmallBold" + height="25" + label="Teleport" + layout="topleft" + left="130" + name="teleport_btn" + top="0" + width="77" /> + <button + follows="bottom|right" + font="SansSerifSmallBold" + height="25" + label="v" + layout="topleft" + name="overflow_btn" + right="-10" + top="0" + width="30" /> + </panel> + </panel> + </tab_container> + + <panel + class="sidepanel_object_info" + filename="sidepanel_object_info.xml" + follows="all" + height="360" + layout="topleft" + left="0" + help_topic="objects_info_tab" + name="sidepanel_object_info" + top="30" + visible="false" /> +</panel> diff --git a/indra/newview/skins/default/xui/es/panel_edit_profile.xml b/indra/newview/skins/default/xui/es/panel_edit_profile.xml index bcf4128e01ff20b0531174fc5032f3954b748809..c12dd8d58c1dab2d93e3f65294d0908f72ae52e7 100644 --- a/indra/newview/skins/default/xui/es/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/es/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Residente" /> - <string name="AcctTypeTrial" - value="Prueba" /> - <string name="AcctTypeCharterMember" - value="Miembro fundador" /> - <string name="AcctTypeEmployee" - value="Empleado de Linden Lab" /> - <string name="PaymentInfoUsed" - value="Ha usado una forma de pago" /> - <string name="PaymentInfoOnFile" - value="Hay infor. de la forma de pago" /> - <string name="NoPaymentInfoOnFile" - value="Sin infor. de la forma de pago" /> - <string name="AgeVerified" - value="Edad verificada" /> - <string name="NotAgeVerified" - value="Edad no verificada" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=es - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Compañero/a:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Mensaje en el estado ocupado: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Residente" /> + <string name="AcctTypeTrial" + value="Prueba" /> + <string name="AcctTypeCharterMember" + value="Miembro fundador" /> + <string name="AcctTypeEmployee" + value="Empleado de Linden Lab" /> + <string name="PaymentInfoUsed" + value="Ha usado una forma de pago" /> + <string name="PaymentInfoOnFile" + value="Hay infor. de la forma de pago" /> + <string name="NoPaymentInfoOnFile" + value="Sin infor. de la forma de pago" /> + <string name="AgeVerified" + value="Edad verificada" /> + <string name="NotAgeVerified" + value="Edad no verificada" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=es + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Compañero/a:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Mensaje en el estado ocupado: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_edit_profile.xml b/indra/newview/skins/default/xui/fr/panel_edit_profile.xml index f62ea7c80fb753f1b377ddf34288d223a024dd5f..3a1585bce297a350826ce695b52a559d9e5de370 100644 --- a/indra/newview/skins/default/xui/fr/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/fr/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Résident" /> - <string name="AcctTypeTrial" - value="Essai" /> - <string name="AcctTypeCharterMember" - value="Membre originaire" /> - <string name="AcctTypeEmployee" - value="Employé(e) de Linden Lab" /> - <string name="PaymentInfoUsed" - value="Infos de paiement utilisées" /> - <string name="PaymentInfoOnFile" - value="Infos de paiement enregistrées" /> - <string name="NoPaymentInfoOnFile" - value="Aucune info de paiement" /> - <string name="AgeVerified" - value="Âge vérifié" /> - <string name="NotAgeVerified" - value="Âge non vérifié" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=fr - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Partenaire :"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Réponse si occupé(e) : - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Résident" /> + <string name="AcctTypeTrial" + value="Essai" /> + <string name="AcctTypeCharterMember" + value="Membre originaire" /> + <string name="AcctTypeEmployee" + value="Employé(e) de Linden Lab" /> + <string name="PaymentInfoUsed" + value="Infos de paiement utilisées" /> + <string name="PaymentInfoOnFile" + value="Infos de paiement enregistrées" /> + <string name="NoPaymentInfoOnFile" + value="Aucune info de paiement" /> + <string name="AgeVerified" + value="Âge vérifié" /> + <string name="NotAgeVerified" + value="Âge non vérifié" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=fr + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Partenaire :"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Réponse si occupé(e) : + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/it/panel_edit_profile.xml b/indra/newview/skins/default/xui/it/panel_edit_profile.xml index 0eba7bf3b69d43b70e41ed5e9f5f1a5c16152e6b..33f3c367c2e8eb7e8cc635035a94e642d14ad1cf 100644 --- a/indra/newview/skins/default/xui/it/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/it/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Residente" /> - <string name="AcctTypeTrial" - value="Prova" /> - <string name="AcctTypeCharterMember" - value="Membro privilegiato" /> - <string name="AcctTypeEmployee" - value="Impiegato della Linden Lab" /> - <string name="PaymentInfoUsed" - value="Info. di pagamento usate" /> - <string name="PaymentInfoOnFile" - value="Info. di pagamento in archivio" /> - <string name="NoPaymentInfoOnFile" - value="Nessuna info. di pagamento" /> - <string name="AgeVerified" - value="Età verificata" /> - <string name="NotAgeVerified" - value="Età non verificata" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=it - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Risposta agli IM quando sono in 'Occupato': - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Residente" /> + <string name="AcctTypeTrial" + value="Prova" /> + <string name="AcctTypeCharterMember" + value="Membro privilegiato" /> + <string name="AcctTypeEmployee" + value="Impiegato della Linden Lab" /> + <string name="PaymentInfoUsed" + value="Info. di pagamento usate" /> + <string name="PaymentInfoOnFile" + value="Info. di pagamento in archivio" /> + <string name="NoPaymentInfoOnFile" + value="Nessuna info. di pagamento" /> + <string name="AgeVerified" + value="Età verificata" /> + <string name="NotAgeVerified" + value="Età non verificata" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=it + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Partner:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Risposta agli IM quando sono in 'Occupato': + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_edit_profile.xml b/indra/newview/skins/default/xui/ja/panel_edit_profile.xml index ca4ab3e773f09869bfb79424b2272b227009991c..2cf8456187f9d69f6fa168bdd35dd09a5a89290c 100644 --- a/indra/newview/skins/default/xui/ja/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/ja/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="ä½äºº" /> - <string name="AcctTypeTrial" - value="トライアル" /> - <string name="AcctTypeCharterMember" - value="特権メンãƒãƒ¼" /> - <string name="AcctTypeEmployee" - value="Linden Lab従æ¥å“¡" /> - <string name="PaymentInfoUsed" - value="支払ã„æƒ…å ±ç™»éŒ²æ¸ˆ" /> - <string name="PaymentInfoOnFile" - value="支払ã„æƒ…å ±ç™»éŒ²æ¸ˆã¿" /> - <string name="NoPaymentInfoOnFile" - value="支払ã„æƒ…å ±æœªç™»éŒ²" /> - <string name="AgeVerified" - value="年齢確èªæ¸ˆã¿" /> - <string name="NotAgeVerified" - value="年齢未確èª" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=ja - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="パートナー:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - å–ã‚Šè¾¼ã¿ä¸å¿œç”メッセージ: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="ä½äºº" /> + <string name="AcctTypeTrial" + value="トライアル" /> + <string name="AcctTypeCharterMember" + value="特権メンãƒãƒ¼" /> + <string name="AcctTypeEmployee" + value="Linden Lab従æ¥å“¡" /> + <string name="PaymentInfoUsed" + value="支払ã„æƒ…å ±ç™»éŒ²æ¸ˆ" /> + <string name="PaymentInfoOnFile" + value="支払ã„æƒ…å ±ç™»éŒ²æ¸ˆã¿" /> + <string name="NoPaymentInfoOnFile" + value="支払ã„æƒ…å ±æœªç™»éŒ²" /> + <string name="AgeVerified" + value="年齢確èªæ¸ˆã¿" /> + <string name="NotAgeVerified" + value="年齢未確èª" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=ja + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="パートナー:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + å–ã‚Šè¾¼ã¿ä¸å¿œç”メッセージ: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/nl/panel_edit_profile.xml b/indra/newview/skins/default/xui/nl/panel_edit_profile.xml index 00f8c087de94185cc423c228fe2d6e4476ddfa1c..172395e20a27b6ca938f09d58240b33ee8ac636e 100644 --- a/indra/newview/skins/default/xui/nl/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/nl/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Inwoner" /> - <string name="AcctTypeTrial" - value="Proef" /> - <string name="AcctTypeCharterMember" - value="Charter lid" /> - <string name="AcctTypeEmployee" - value="Linden Lab werknemer" /> - <string name="PaymentInfoUsed" - value="Betalingsinformatie gebruikt" /> - <string name="PaymentInfoOnFile" - value="Betalingsinformatie aanwezig" /> - <string name="NoPaymentInfoOnFile" - value="Geen betalingsinfo aanwezig" /> - <string name="AgeVerified" - value="Leeftijd geverifieerd" /> - <string name="NotAgeVerified" - value="Leeftijd niet geverifieerd" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=nl - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Antwoord bij Niet Storen: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Inwoner" /> + <string name="AcctTypeTrial" + value="Proef" /> + <string name="AcctTypeCharterMember" + value="Charter lid" /> + <string name="AcctTypeEmployee" + value="Linden Lab werknemer" /> + <string name="PaymentInfoUsed" + value="Betalingsinformatie gebruikt" /> + <string name="PaymentInfoOnFile" + value="Betalingsinformatie aanwezig" /> + <string name="NoPaymentInfoOnFile" + value="Geen betalingsinfo aanwezig" /> + <string name="AgeVerified" + value="Leeftijd geverifieerd" /> + <string name="NotAgeVerified" + value="Leeftijd niet geverifieerd" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=nl + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Partner:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Antwoord bij Niet Storen: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_profile.xml b/indra/newview/skins/default/xui/pl/panel_edit_profile.xml index e449a92d7e58796c1339edb9b4d6afa48f3b3768..97fa3118f8fd4c45c57c3f863e1adbfdfc933b7e 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Rezydent" /> - <string name="AcctTypeTrial" - value="Próbne" /> - <string name="AcctTypeCharterMember" - value="CzÅ‚onek-zalożyciel" /> - <string name="AcctTypeEmployee" - value="Pracownik Linden Lab" /> - <string name="PaymentInfoUsed" - value="Dane Konta Używane" /> - <string name="PaymentInfoOnFile" - value="Dane Konta DostÄ™pne" /> - <string name="NoPaymentInfoOnFile" - value="Brak Danych Konta" /> - <string name="AgeVerified" - value="Wiek Zweryfikowany" /> - <string name="NotAgeVerified" - value="Brak Weryfikacji Wieku" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=pl - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - PracuÅ› Mówi: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Rezydent" /> + <string name="AcctTypeTrial" + value="Próbne" /> + <string name="AcctTypeCharterMember" + value="CzÅ‚onek-zalożyciel" /> + <string name="AcctTypeEmployee" + value="Pracownik Linden Lab" /> + <string name="PaymentInfoUsed" + value="Dane Konta Używane" /> + <string name="PaymentInfoOnFile" + value="Dane Konta DostÄ™pne" /> + <string name="NoPaymentInfoOnFile" + value="Brak Danych Konta" /> + <string name="AgeVerified" + value="Wiek Zweryfikowany" /> + <string name="NotAgeVerified" + value="Brak Weryfikacji Wieku" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=pl + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Partner:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + PracuÅ› Mówi: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_edit_profile.xml b/indra/newview/skins/default/xui/pt/panel_edit_profile.xml index e97e77cfe6f69cbe1fd9f6da732f0e9f216ccc60..a989cab16718680136f46cdac23e7ab24f6354f9 100644 --- a/indra/newview/skins/default/xui/pt/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/pt/panel_edit_profile.xml @@ -1,45 +1,45 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="edit_profile_panel"> - <string name="CaptionTextAcctInfo"> - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - </string> - <string name="AcctTypeResident" - value="Residente" /> - <string name="AcctTypeTrial" - value="Teste" /> - <string name="AcctTypeCharterMember" - value="Estatuto do membro" /> - <string name="AcctTypeEmployee" - value="Contratado da Linden Lab" /> - <string name="PaymentInfoUsed" - value="Infor. de pagamento utilizadas" /> - <string name="PaymentInfoOnFile" - value="Infor. de pagamento no arquivo" /> - <string name="NoPaymentInfoOnFile" - value="Sem infor. de pagamento no arquivo" /> - <string name="AgeVerified" - value="Idade Verificada" /> - <string name="NotAgeVerified" - value="Idade não Verificada" /> - <string name="partner_edit_link_url"> - http://www.secondlife.com/account/partners.php?lang=pt - </string> - <panel name="scroll_content_panel"> - <panel name="data_panel" > - <panel name="lifes_images_panel"> - <panel name="second_life_image_panel"> - <text name="second_life_photo_title_text"> - [SECOND_LIFE]: - </text> - </panel> - </panel> - <text name="title_partner_text" value="Parceiro:"/> - <panel name="partner_data_panel"> - <text name="partner_text" value="[FIRST] [LAST]"/> - </panel> - <text name="text_box3"> - Resposta no Modo Ocupado: - </text> - </panel> - </panel> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="edit_profile_panel"> + <string name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string name="AcctTypeResident" + value="Residente" /> + <string name="AcctTypeTrial" + value="Teste" /> + <string name="AcctTypeCharterMember" + value="Estatuto do membro" /> + <string name="AcctTypeEmployee" + value="Contratado da Linden Lab" /> + <string name="PaymentInfoUsed" + value="Infor. de pagamento utilizadas" /> + <string name="PaymentInfoOnFile" + value="Infor. de pagamento no arquivo" /> + <string name="NoPaymentInfoOnFile" + value="Sem infor. de pagamento no arquivo" /> + <string name="AgeVerified" + value="Idade Verificada" /> + <string name="NotAgeVerified" + value="Idade não Verificada" /> + <string name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=pt + </string> + <panel name="scroll_content_panel"> + <panel name="data_panel" > + <panel name="lifes_images_panel"> + <panel name="second_life_image_panel"> + <text name="second_life_photo_title_text"> + [SECOND_LIFE]: + </text> + </panel> + </panel> + <text name="title_partner_text" value="Parceiro:"/> + <panel name="partner_data_panel"> + <text name="partner_text" value="[FIRST] [LAST]"/> + </panel> + <text name="text_box3"> + Resposta no Modo Ocupado: + </text> + </panel> + </panel> +</panel> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 009be35f641390be0b032aaee9355d0c85694733..d31a81e1280ae0f5be8087fee28d218cf56db24a 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -1,423 +1,423 @@ -/** - * @file lllogininstance_test.cpp - * @brief Test for lllogininstance.cpp. - * - * $LicenseInfo:firstyear=2008&license=internal$ - * Copyright (c) 2008, Linden Research, Inc. - * $/LicenseInfo$ - */ - -// Precompiled header -#include "../llviewerprecompiledheaders.h" -// Own header -#include "../lllogininstance.h" -// STL headers -// std headers -// external library headers -// other Linden headers -#include "../test/lltut.h" -#include "llevents.h" - -#if defined(LL_WINDOWS) -#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr -#endif - -// Constants -const std::string VIEWERLOGIN_URI("viewerlogin_uri"); -const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid"); - -const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno"); - -// Link seams. - -//----------------------------------------------------------------------------- -static LLEventStream gTestPump("test_pump"); - -#include "lllogin.h" -static std::string gLoginURI; -static LLSD gLoginCreds; -static bool gDisconnectCalled = false; -class LLLogin::Impl -{ -}; -LLLogin::LLLogin() {} -LLLogin::~LLLogin() {} -LLEventPump& LLLogin::getEventPump() { return gTestPump; } -void LLLogin::connect(const std::string& uri, const LLSD& credentials) -{ - gLoginURI = uri; - gLoginCreds = credentials; -} - -void LLLogin::disconnect() -{ - gDisconnectCalled = true; -} - -//----------------------------------------------------------------------------- -#include "../llviewernetwork.h" -unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'}; /* Flawfinder: ignore */ - -LLViewerLogin::LLViewerLogin() {} -LLViewerLogin::~LLViewerLogin() {} -void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const -{ - uris.push_back(VIEWERLOGIN_URI); -} -std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; } - -//----------------------------------------------------------------------------- -#include "../llviewercontrol.h" -LLControlGroup gSavedSettings("Global"); -std::string gCurrentVersion = "invalid_version"; - -LLControlGroup::LLControlGroup(const std::string& name) : - LLInstanceTracker<LLControlGroup, std::string>(name){} -LLControlGroup::~LLControlGroup() {} -void LLControlGroup::setBOOL(const std::string& name, BOOL val) {} -BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; } -U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; } -void LLControlGroup::setString(const std::string& name, const std::string& val) {} -std::string LLControlGroup::getString(const std::string& name) { return "test_string"; } -BOOL LLControlGroup::declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, BOOL persist) { return TRUE; } -BOOL LLControlGroup::declareString(const std::string& name, const std::string &initial_val, const std::string& comment, BOOL persist) { return TRUE; } - -#include "lluicolortable.h" -void LLUIColorTable::saveUserSettings(void)const {} - -//----------------------------------------------------------------------------- -#include "../llurlsimstring.h" -LLURLSimString LLURLSimString::sInstance; -bool LLURLSimString::parse() { return true; } - -//----------------------------------------------------------------------------- -#include "llnotifications.h" -#include "llfloaterreg.h" -static std::string gTOSType; -static LLEventPump * gTOSReplyPump = NULL; - -//static -LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) -{ - gTOSType = name; - gTOSReplyPump = &LLEventPumps::instance().obtain(key["reply_pump"]); - return NULL; -} - -//----------------------------------------------------------------------------- -// LLNotifications -class MockNotifications : public LLNotificationsInterface -{ - boost::function<void (const LLSD&, const LLSD&)> mResponder; - int mAddedCount; - -public: - MockNotifications() : - mResponder(0), - mAddedCount(0) - { - } - - virtual ~MockNotifications() {} - - /* virtual */ LLNotificationPtr add( - const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - LLNotificationFunctorRegistry::ResponseFunctor functor) - { - mResponder = functor; - mAddedCount++; - return LLNotificationPtr((LLNotification*)NULL); - } - - void sendYesResponse() - { - LLSD notification; - LLSD response; - response = 1; - mResponder(notification, response); - } - - void sendNoResponse() - { - LLSD notification; - LLSD response; - response = 2; - mResponder(notification, response); - } - - void sendBogusResponse() - { - LLSD notification; - LLSD response; - response = 666; - mResponder(notification, response); - } - - int addedCount() { return mAddedCount; } -}; - -S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response) -{ - return response.asInteger(); -} - -// misc -std::string xml_escape_string(const std::string& in) -{ - return in; -} - -/***************************************************************************** -* TUT -*****************************************************************************/ -namespace tut -{ - struct lllogininstance_data - { - lllogininstance_data() : logininstance(LLLoginInstance::getInstance()) - { - // Global initialization - gLoginURI.clear(); - gLoginCreds.clear(); - gDisconnectCalled = false; - - gTOSType = ""; // Set to invalid value. - gTOSReplyPump = 0; // clear the callback. - - - gSavedSettings.declareBOOL("NoInventoryLibrary", FALSE, "", FALSE); - gSavedSettings.declareBOOL("ConnectAsGod", FALSE, "", FALSE); - gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE); - gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE); - gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE); - gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE); - gSavedSettings.declareString("NextLoginLocation", "", "", FALSE); - gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE); - - credentials["first"] = "testfirst"; - credentials["last"] = "testlast"; - credentials["passwd"] = "testpass"; - - logininstance->setNotificationsInterface(¬ifications); - } - - LLLoginInstance* logininstance; - LLSD credentials; - MockNotifications notifications; - }; - - typedef test_group<lllogininstance_data> lllogininstance_group; - typedef lllogininstance_group::object lllogininstance_object; - lllogininstance_group llsdmgr("lllogininstance"); - - template<> template<> - void lllogininstance_object::test<1>() - { - set_test_name("Test Simple Success And Disconnect"); - - // Test default connect. - logininstance->connect(credentials); - - ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); - - // Dummy success response. - LLSD response; - response["state"] = "online"; - response["change"] = "connect"; - response["progress"] = 1.0; - response["transfer_rate"] = 7; - response["data"] = "test_data"; - - gTestPump.post(response); - - ensure("Success response", logininstance->authSuccess()); - ensure_equals("Test Response Data", logininstance->getResponse().asString(), "test_data"); - - logininstance->disconnect(); - - ensure_equals("Called Login Module Disconnect", gDisconnectCalled, true); - - response.clear(); - response["state"] = "offline"; - response["change"] = "disconnect"; - response["progress"] = 0.0; - response["transfer_rate"] = 0; - response["data"] = "test_data"; - - gTestPump.post(response); - - ensure("Disconnected", !(logininstance->authSuccess())); - } - - template<> template<> - void lllogininstance_object::test<2>() - { - set_test_name("Test User TOS/Critical message Interaction"); - - const std::string test_uri = "testing-uri"; - - // Test default connect. - logininstance->connect(test_uri, credentials); - - // connect should call LLLogin::connect to init gLoginURI and gLoginCreds. - ensure_equals("Default connect uri", gLoginURI, "testing-uri"); - ensure_equals("Default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); - ensure_equals("Default for read critical", gLoginCreds["params"]["read_critical"].asBoolean(), false); - - // TOS failure response. - LLSD response; - response["state"] = "offline"; - response["change"] = "fail.login"; - response["progress"] = 0.0; - response["transfer_rate"] = 7; - response["data"]["reason"] = "tos"; - gTestPump.post(response); - - ensure_equals("TOS Dialog type", gTOSType, "message_tos"); - ensure("TOS callback given", gTOSReplyPump != 0); - gTOSReplyPump->post(false); // Call callback denying TOS. - ensure("No TOS, failed auth", logininstance->authFailure()); - - // Start again. - logininstance->connect(test_uri, credentials); - gTestPump.post(response); // Fail for tos again. - gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos. - ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true); - ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); - - // Fail connection, attempt connect again. - // The new request should have reset agree to tos to default. - response["data"]["reason"] = "key"; // bad creds. - gTestPump.post(response); - ensure("TOS auth failure", logininstance->authFailure()); - - logininstance->connect(test_uri, credentials); - ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); - - // Critical Message failure response. - logininstance->connect(test_uri, credentials); - response["data"]["reason"] = "critical"; // Change response to "critical message" - gTestPump.post(response); - - ensure_equals("TOS Dialog type", gTOSType, "message_critical"); - ensure("TOS callback given", gTOSReplyPump != 0); - gTOSReplyPump->post(true); - ensure_equals("Accepted read critical message", gLoginCreds["params"]["read_critical"].asBoolean(), true); - ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); - - // Fail then attempt new connection - response["data"]["reason"] = "key"; // bad creds. - gTestPump.post(response); - ensure("TOS auth failure", logininstance->authFailure()); - logininstance->connect(test_uri, credentials); - ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false); - } - - template<> template<> - void lllogininstance_object::test<3>() - { - set_test_name("Test Mandatory Update User Accepts"); - - // Part 1 - Mandatory Update, with User accepts response. - // Test connect with update needed. - logininstance->connect(credentials); - - ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); - - // Update needed failure response. - LLSD response; - response["state"] = "offline"; - response["change"] = "fail.login"; - response["progress"] = 0.0; - response["transfer_rate"] = 7; - response["data"]["reason"] = "update"; - gTestPump.post(response); - - ensure_equals("Notification added", notifications.addedCount(), 1); - - notifications.sendYesResponse(); - - ensure("Disconnected", !(logininstance->authSuccess())); - } - - template<> template<> - void lllogininstance_object::test<4>() - { - set_test_name("Test Mandatory Update User Decline"); - - // Test connect with update needed. - logininstance->connect(credentials); - - ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); - - // Update needed failure response. - LLSD response; - response["state"] = "offline"; - response["change"] = "fail.login"; - response["progress"] = 0.0; - response["transfer_rate"] = 7; - response["data"]["reason"] = "update"; - gTestPump.post(response); - - ensure_equals("Notification added", notifications.addedCount(), 1); - notifications.sendNoResponse(); - - ensure("Disconnected", !(logininstance->authSuccess())); - } - - template<> template<> - void lllogininstance_object::test<6>() - { - set_test_name("Test Optional Update User Accept"); - - // Part 3 - Mandatory Update, with bogus response. - // Test connect with update needed. - logininstance->connect(credentials); - - ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); - - // Update needed failure response. - LLSD response; - response["state"] = "offline"; - response["change"] = "fail.login"; - response["progress"] = 0.0; - response["transfer_rate"] = 7; - response["data"]["reason"] = "optional"; - gTestPump.post(response); - - ensure_equals("Notification added", notifications.addedCount(), 1); - notifications.sendYesResponse(); - - ensure("Disconnected", !(logininstance->authSuccess())); - } - - template<> template<> - void lllogininstance_object::test<7>() - { - set_test_name("Test Optional Update User Denies"); - - // Part 3 - Mandatory Update, with bogus response. - // Test connect with update needed. - logininstance->connect(credentials); - - ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); - - // Update needed failure response. - LLSD response; - response["state"] = "offline"; - response["change"] = "fail.login"; - response["progress"] = 0.0; - response["transfer_rate"] = 7; - response["data"]["reason"] = "optional"; - gTestPump.post(response); - - ensure_equals("Notification added", notifications.addedCount(), 1); - notifications.sendNoResponse(); - - // User skips, should be reconnecting. - ensure_equals("reconnect uri", gLoginURI, VIEWERLOGIN_URI); - ensure_equals("skipping optional update", gLoginCreds["params"]["skipoptional"].asBoolean(), true); - } -} +/** + * @file lllogininstance_test.cpp + * @brief Test for lllogininstance.cpp. + * + * $LicenseInfo:firstyear=2008&license=internal$ + * Copyright (c) 2008, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "../llviewerprecompiledheaders.h" +// Own header +#include "../lllogininstance.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "llevents.h" + +#if defined(LL_WINDOWS) +#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr +#endif + +// Constants +const std::string VIEWERLOGIN_URI("viewerlogin_uri"); +const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid"); + +const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno"); + +// Link seams. + +//----------------------------------------------------------------------------- +static LLEventStream gTestPump("test_pump"); + +#include "lllogin.h" +static std::string gLoginURI; +static LLSD gLoginCreds; +static bool gDisconnectCalled = false; +class LLLogin::Impl +{ +}; +LLLogin::LLLogin() {} +LLLogin::~LLLogin() {} +LLEventPump& LLLogin::getEventPump() { return gTestPump; } +void LLLogin::connect(const std::string& uri, const LLSD& credentials) +{ + gLoginURI = uri; + gLoginCreds = credentials; +} + +void LLLogin::disconnect() +{ + gDisconnectCalled = true; +} + +//----------------------------------------------------------------------------- +#include "../llviewernetwork.h" +unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'}; /* Flawfinder: ignore */ + +LLViewerLogin::LLViewerLogin() {} +LLViewerLogin::~LLViewerLogin() {} +void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const +{ + uris.push_back(VIEWERLOGIN_URI); +} +std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; } + +//----------------------------------------------------------------------------- +#include "../llviewercontrol.h" +LLControlGroup gSavedSettings("Global"); +std::string gCurrentVersion = "invalid_version"; + +LLControlGroup::LLControlGroup(const std::string& name) : + LLInstanceTracker<LLControlGroup, std::string>(name){} +LLControlGroup::~LLControlGroup() {} +void LLControlGroup::setBOOL(const std::string& name, BOOL val) {} +BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; } +U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; } +void LLControlGroup::setString(const std::string& name, const std::string& val) {} +std::string LLControlGroup::getString(const std::string& name) { return "test_string"; } +BOOL LLControlGroup::declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, BOOL persist) { return TRUE; } +BOOL LLControlGroup::declareString(const std::string& name, const std::string &initial_val, const std::string& comment, BOOL persist) { return TRUE; } + +#include "lluicolortable.h" +void LLUIColorTable::saveUserSettings(void)const {} + +//----------------------------------------------------------------------------- +#include "../llurlsimstring.h" +LLURLSimString LLURLSimString::sInstance; +bool LLURLSimString::parse() { return true; } + +//----------------------------------------------------------------------------- +#include "llnotifications.h" +#include "llfloaterreg.h" +static std::string gTOSType; +static LLEventPump * gTOSReplyPump = NULL; + +//static +LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) +{ + gTOSType = name; + gTOSReplyPump = &LLEventPumps::instance().obtain(key["reply_pump"]); + return NULL; +} + +//----------------------------------------------------------------------------- +// LLNotifications +class MockNotifications : public LLNotificationsInterface +{ + boost::function<void (const LLSD&, const LLSD&)> mResponder; + int mAddedCount; + +public: + MockNotifications() : + mResponder(0), + mAddedCount(0) + { + } + + virtual ~MockNotifications() {} + + /* virtual */ LLNotificationPtr add( + const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + LLNotificationFunctorRegistry::ResponseFunctor functor) + { + mResponder = functor; + mAddedCount++; + return LLNotificationPtr((LLNotification*)NULL); + } + + void sendYesResponse() + { + LLSD notification; + LLSD response; + response = 1; + mResponder(notification, response); + } + + void sendNoResponse() + { + LLSD notification; + LLSD response; + response = 2; + mResponder(notification, response); + } + + void sendBogusResponse() + { + LLSD notification; + LLSD response; + response = 666; + mResponder(notification, response); + } + + int addedCount() { return mAddedCount; } +}; + +S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response) +{ + return response.asInteger(); +} + +// misc +std::string xml_escape_string(const std::string& in) +{ + return in; +} + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct lllogininstance_data + { + lllogininstance_data() : logininstance(LLLoginInstance::getInstance()) + { + // Global initialization + gLoginURI.clear(); + gLoginCreds.clear(); + gDisconnectCalled = false; + + gTOSType = ""; // Set to invalid value. + gTOSReplyPump = 0; // clear the callback. + + + gSavedSettings.declareBOOL("NoInventoryLibrary", FALSE, "", FALSE); + gSavedSettings.declareBOOL("ConnectAsGod", FALSE, "", FALSE); + gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE); + gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE); + gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE); + gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE); + gSavedSettings.declareString("NextLoginLocation", "", "", FALSE); + gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE); + + credentials["first"] = "testfirst"; + credentials["last"] = "testlast"; + credentials["passwd"] = "testpass"; + + logininstance->setNotificationsInterface(¬ifications); + } + + LLLoginInstance* logininstance; + LLSD credentials; + MockNotifications notifications; + }; + + typedef test_group<lllogininstance_data> lllogininstance_group; + typedef lllogininstance_group::object lllogininstance_object; + lllogininstance_group llsdmgr("lllogininstance"); + + template<> template<> + void lllogininstance_object::test<1>() + { + set_test_name("Test Simple Success And Disconnect"); + + // Test default connect. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Dummy success response. + LLSD response; + response["state"] = "online"; + response["change"] = "connect"; + response["progress"] = 1.0; + response["transfer_rate"] = 7; + response["data"] = "test_data"; + + gTestPump.post(response); + + ensure("Success response", logininstance->authSuccess()); + ensure_equals("Test Response Data", logininstance->getResponse().asString(), "test_data"); + + logininstance->disconnect(); + + ensure_equals("Called Login Module Disconnect", gDisconnectCalled, true); + + response.clear(); + response["state"] = "offline"; + response["change"] = "disconnect"; + response["progress"] = 0.0; + response["transfer_rate"] = 0; + response["data"] = "test_data"; + + gTestPump.post(response); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<2>() + { + set_test_name("Test User TOS/Critical message Interaction"); + + const std::string test_uri = "testing-uri"; + + // Test default connect. + logininstance->connect(test_uri, credentials); + + // connect should call LLLogin::connect to init gLoginURI and gLoginCreds. + ensure_equals("Default connect uri", gLoginURI, "testing-uri"); + ensure_equals("Default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); + ensure_equals("Default for read critical", gLoginCreds["params"]["read_critical"].asBoolean(), false); + + // TOS failure response. + LLSD response; + response["state"] = "offline"; + response["change"] = "fail.login"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "tos"; + gTestPump.post(response); + + ensure_equals("TOS Dialog type", gTOSType, "message_tos"); + ensure("TOS callback given", gTOSReplyPump != 0); + gTOSReplyPump->post(false); // Call callback denying TOS. + ensure("No TOS, failed auth", logininstance->authFailure()); + + // Start again. + logininstance->connect(test_uri, credentials); + gTestPump.post(response); // Fail for tos again. + gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos. + ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true); + ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); + + // Fail connection, attempt connect again. + // The new request should have reset agree to tos to default. + response["data"]["reason"] = "key"; // bad creds. + gTestPump.post(response); + ensure("TOS auth failure", logininstance->authFailure()); + + logininstance->connect(test_uri, credentials); + ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); + + // Critical Message failure response. + logininstance->connect(test_uri, credentials); + response["data"]["reason"] = "critical"; // Change response to "critical message" + gTestPump.post(response); + + ensure_equals("TOS Dialog type", gTOSType, "message_critical"); + ensure("TOS callback given", gTOSReplyPump != 0); + gTOSReplyPump->post(true); + ensure_equals("Accepted read critical message", gLoginCreds["params"]["read_critical"].asBoolean(), true); + ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); + + // Fail then attempt new connection + response["data"]["reason"] = "key"; // bad creds. + gTestPump.post(response); + ensure("TOS auth failure", logininstance->authFailure()); + logininstance->connect(test_uri, credentials); + ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false); + } + + template<> template<> + void lllogininstance_object::test<3>() + { + set_test_name("Test Mandatory Update User Accepts"); + + // Part 1 - Mandatory Update, with User accepts response. + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["change"] = "fail.login"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "update"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + + notifications.sendYesResponse(); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<4>() + { + set_test_name("Test Mandatory Update User Decline"); + + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["change"] = "fail.login"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "update"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + notifications.sendNoResponse(); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<6>() + { + set_test_name("Test Optional Update User Accept"); + + // Part 3 - Mandatory Update, with bogus response. + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["change"] = "fail.login"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "optional"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + notifications.sendYesResponse(); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<7>() + { + set_test_name("Test Optional Update User Denies"); + + // Part 3 - Mandatory Update, with bogus response. + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["change"] = "fail.login"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "optional"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + notifications.sendNoResponse(); + + // User skips, should be reconnecting. + ensure_equals("reconnect uri", gLoginURI, VIEWERLOGIN_URI); + ensure_equals("skipping optional update", gLoginCreds["params"]["skipoptional"].asBoolean(), true); + } +} diff --git a/indra/tools/vstool/README.txt b/indra/tools/vstool/README.txt index e4191800312f49e8906997534d3ed4ac603d2341..6f64aa41df08c227e0ef421d53fc260b83bf8293 100644 --- a/indra/tools/vstool/README.txt +++ b/indra/tools/vstool/README.txt @@ -1,9 +1,9 @@ -VSTool is a command line utility to manipulate VisualStudio settings. - -The windows cmake project configuration uses VSTool.exe - -A handy upgrade: - figure out how to make cmake build this csharp app - - or write the app using script (jscript?!?) so it doesn't need to be built. - - +VSTool is a command line utility to manipulate VisualStudio settings. + +The windows cmake project configuration uses VSTool.exe + +A handy upgrade: + figure out how to make cmake build this csharp app + - or write the app using script (jscript?!?) so it doesn't need to be built. + + diff --git a/indra/tools/vstool/VSTool.csproj b/indra/tools/vstool/VSTool.csproj index 24f1031f81b6151db8ea20628ee974ff35d18626..5d8764b6bffde9415aa5d0fb326ea949bc4d884c 100644 --- a/indra/tools/vstool/VSTool.csproj +++ b/indra/tools/vstool/VSTool.csproj @@ -1,95 +1,95 @@ -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectType>Local</ProjectType> - <ProductVersion>8.0.50727</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{96943E2D-1373-4617-A117-D0F997A94919}</ProjectGuid> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ApplicationIcon> - </ApplicationIcon> - <AssemblyKeyContainerName> - </AssemblyKeyContainerName> - <AssemblyName>VSTool</AssemblyName> - <AssemblyOriginatorKeyFile> - </AssemblyOriginatorKeyFile> - <DefaultClientScript>JScript</DefaultClientScript> - <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout> - <DefaultTargetSchema>IE50</DefaultTargetSchema> - <DelaySign>false</DelaySign> - <OutputType>Exe</OutputType> - <RootNamespace>VSTool</RootNamespace> - <RunPostBuildEvent>Always</RunPostBuildEvent> - <StartupObject>VSTool.VSToolMain</StartupObject> - <FileUpgradeFlags> - </FileUpgradeFlags> - <UpgradeBackupLocation> - </UpgradeBackupLocation> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <OutputPath>.\</OutputPath> - <AllowUnsafeBlocks>false</AllowUnsafeBlocks> - <BaseAddress>285212672</BaseAddress> - <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> - <ConfigurationOverrideFile> - </ConfigurationOverrideFile> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <DocumentationFile> - </DocumentationFile> - <DebugSymbols>true</DebugSymbols> - <FileAlignment>4096</FileAlignment> - <NoStdLib>false</NoStdLib> - <NoWarn> - </NoWarn> - <Optimize>false</Optimize> - <RegisterForComInterop>false</RegisterForComInterop> - <RemoveIntegerChecks>false</RemoveIntegerChecks> - <TreatWarningsAsErrors>false</TreatWarningsAsErrors> - <WarningLevel>4</WarningLevel> - <DebugType>full</DebugType> - <ErrorReport>prompt</ErrorReport> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <OutputPath>.\</OutputPath> - <AllowUnsafeBlocks>false</AllowUnsafeBlocks> - <BaseAddress>285212672</BaseAddress> - <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> - <ConfigurationOverrideFile> - </ConfigurationOverrideFile> - <DefineConstants>TRACE</DefineConstants> - <DocumentationFile> - </DocumentationFile> - <DebugSymbols>false</DebugSymbols> - <FileAlignment>4096</FileAlignment> - <NoStdLib>false</NoStdLib> - <NoWarn> - </NoWarn> - <Optimize>true</Optimize> - <RegisterForComInterop>false</RegisterForComInterop> - <RemoveIntegerChecks>false</RemoveIntegerChecks> - <TreatWarningsAsErrors>false</TreatWarningsAsErrors> - <WarningLevel>4</WarningLevel> - <DebugType>none</DebugType> - <ErrorReport>prompt</ErrorReport> - </PropertyGroup> - <ItemGroup> - <Reference Include="System"> - <Name>System</Name> - </Reference> - <Reference Include="System.Data"> - <Name>System.Data</Name> - </Reference> - </ItemGroup> - <ItemGroup> - <Compile Include="main.cs"> - <SubType>Code</SubType> - </Compile> - </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <PropertyGroup> - <PreBuildEvent> - </PreBuildEvent> - <PostBuildEvent> - </PostBuildEvent> - </PropertyGroup> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectType>Local</ProjectType> + <ProductVersion>8.0.50727</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{96943E2D-1373-4617-A117-D0F997A94919}</ProjectGuid> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ApplicationIcon> + </ApplicationIcon> + <AssemblyKeyContainerName> + </AssemblyKeyContainerName> + <AssemblyName>VSTool</AssemblyName> + <AssemblyOriginatorKeyFile> + </AssemblyOriginatorKeyFile> + <DefaultClientScript>JScript</DefaultClientScript> + <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout> + <DefaultTargetSchema>IE50</DefaultTargetSchema> + <DelaySign>false</DelaySign> + <OutputType>Exe</OutputType> + <RootNamespace>VSTool</RootNamespace> + <RunPostBuildEvent>Always</RunPostBuildEvent> + <StartupObject>VSTool.VSToolMain</StartupObject> + <FileUpgradeFlags> + </FileUpgradeFlags> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <OutputPath>.\</OutputPath> + <AllowUnsafeBlocks>false</AllowUnsafeBlocks> + <BaseAddress>285212672</BaseAddress> + <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> + <ConfigurationOverrideFile> + </ConfigurationOverrideFile> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DocumentationFile> + </DocumentationFile> + <DebugSymbols>true</DebugSymbols> + <FileAlignment>4096</FileAlignment> + <NoStdLib>false</NoStdLib> + <NoWarn> + </NoWarn> + <Optimize>false</Optimize> + <RegisterForComInterop>false</RegisterForComInterop> + <RemoveIntegerChecks>false</RemoveIntegerChecks> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <WarningLevel>4</WarningLevel> + <DebugType>full</DebugType> + <ErrorReport>prompt</ErrorReport> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <OutputPath>.\</OutputPath> + <AllowUnsafeBlocks>false</AllowUnsafeBlocks> + <BaseAddress>285212672</BaseAddress> + <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> + <ConfigurationOverrideFile> + </ConfigurationOverrideFile> + <DefineConstants>TRACE</DefineConstants> + <DocumentationFile> + </DocumentationFile> + <DebugSymbols>false</DebugSymbols> + <FileAlignment>4096</FileAlignment> + <NoStdLib>false</NoStdLib> + <NoWarn> + </NoWarn> + <Optimize>true</Optimize> + <RegisterForComInterop>false</RegisterForComInterop> + <RemoveIntegerChecks>false</RemoveIntegerChecks> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <WarningLevel>4</WarningLevel> + <DebugType>none</DebugType> + <ErrorReport>prompt</ErrorReport> + </PropertyGroup> + <ItemGroup> + <Reference Include="System"> + <Name>System</Name> + </Reference> + <Reference Include="System.Data"> + <Name>System.Data</Name> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="main.cs"> + <SubType>Code</SubType> + </Compile> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <PropertyGroup> + <PreBuildEvent> + </PreBuildEvent> + <PostBuildEvent> + </PostBuildEvent> + </PropertyGroup> </Project> \ No newline at end of file diff --git a/indra/tools/vstool/VSTool.sln b/indra/tools/vstool/VSTool.sln index 88596718028cca0ba134e2b2cf11ba6c5a81cbdf..543a0a2efcfaea9bc9fc14f8bc93ce0f07f8b56d 100644 --- a/indra/tools/vstool/VSTool.sln +++ b/indra/tools/vstool/VSTool.sln @@ -1,19 +1,19 @@ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSTool", "VSTool.csproj", "{96943E2D-1373-4617-A117-D0F997A94919}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSTool", "VSTool.csproj", "{96943E2D-1373-4617-A117-D0F997A94919}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs index cc268d59d98f5b8a9b5be55d6dfa39bc3e0b0d73..5c41c916e2e34bcab3859a37b25f5204cad71789 100644 --- a/indra/tools/vstool/main.cs +++ b/indra/tools/vstool/main.cs @@ -1,711 +1,711 @@ -// Code about getting running instances visual studio -// was borrowed from -// http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx - - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using Microsoft.CSharp; - -namespace VSTool -{ - // The MessageFilter class comes from: - // http://msdn.microsoft.com/en-us/library/ms228772(VS.80).aspx - // It allows vstool to get timing error messages from - // visualstudio and handle them. - public class MessageFilter : IOleMessageFilter - { - // - // Class containing the IOleMessageFilter - // thread error-handling functions. - - // Start the filter. - public static void Register() - { - IOleMessageFilter newFilter = new MessageFilter(); - IOleMessageFilter oldFilter = null; - CoRegisterMessageFilter(newFilter, out oldFilter); - } - - // Done with the filter, close it. - public static void Revoke() - { - IOleMessageFilter oldFilter = null; - CoRegisterMessageFilter(null, out oldFilter); - } - - // - // IOleMessageFilter functions. - // Handle incoming thread requests. - int IOleMessageFilter.HandleInComingCall(int dwCallType, - System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr - lpInterfaceInfo) - { - //Return the flag SERVERCALL_ISHANDLED. - return 0; - } - - // Thread call was rejected, so try again. - int IOleMessageFilter.RetryRejectedCall(System.IntPtr - hTaskCallee, int dwTickCount, int dwRejectType) - { - if (dwRejectType == 2) - // flag = SERVERCALL_RETRYLATER. - { - // Retry the thread call immediately if return >=0 & - // <100. - return 99; - } - // Too busy; cancel call. - return -1; - } - - int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, - int dwTickCount, int dwPendingType) - { - //Return the flag PENDINGMSG_WAITDEFPROCESS. - return 2; - } - - // Implement the IOleMessageFilter interface. - [DllImport("Ole32.dll")] - private static extern int - CoRegisterMessageFilter(IOleMessageFilter newFilter, out - IOleMessageFilter oldFilter); - } - - [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), - InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - interface IOleMessageFilter - { - [PreserveSig] - int HandleInComingCall( - int dwCallType, - IntPtr hTaskCaller, - int dwTickCount, - IntPtr lpInterfaceInfo); - - [PreserveSig] - int RetryRejectedCall( - IntPtr hTaskCallee, - int dwTickCount, - int dwRejectType); - - [PreserveSig] - int MessagePending( - IntPtr hTaskCallee, - int dwTickCount, - int dwPendingType); - } - - class ViaCOM - { - public static object GetProperty(object from_obj, string prop_name) - { - try - { - Type objType = from_obj.GetType(); - return objType.InvokeMember( - prop_name, - BindingFlags.GetProperty, null, - from_obj, - null); - } - catch (Exception e) - { - Console.WriteLine("Error getting property: \"{0}\"", prop_name); - Console.WriteLine(e.Message); - throw e; - } - } - - public static object SetProperty(object from_obj, string prop_name, object new_value) - { - try - { - object[] args = { new_value }; - Type objType = from_obj.GetType(); - return objType.InvokeMember( - prop_name, - BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.SetProperty, - null, - from_obj, - args); - } - catch (Exception e) - { - Console.WriteLine("Error setting property: \"{0}\"", prop_name); - Console.WriteLine(e.Message); - throw e; - } - } - - public static object CallMethod(object from_obj, string method_name, params object[] args) - { - try - { - Type objType = from_obj.GetType(); - return objType.InvokeMember( - method_name, - BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.InvokeMethod, - null, - from_obj, - args); - } - catch (Exception e) - { - Console.WriteLine("Error calling method \"{0}\"", method_name); - Console.WriteLine(e.Message); - throw e; - } - } - }; - - /// <summary> - /// The main entry point class for VSTool. - /// </summary> - class VSToolMain - { - #region Interop imports - [DllImport("ole32.dll")] - public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); - - [DllImport("ole32.dll")] - public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); - #endregion - - static System.Boolean ignore_case = true; - - static string solution_name = null; - static bool use_new_vs = false; - static Hashtable projectDict = new Hashtable(); - static string startup_project = null; - static string config = null; - - static object dte = null; - static object solution = null; - - /// <summary> - /// The main entry point for the application. - /// </summary> - [STAThread] - static int Main(string[] args) - { - int retVal = 0; - bool need_save = false; - - try - { - parse_command_line(args); - - Console.WriteLine("Editing solution: {0}", solution_name); - - bool found_open_solution = GetDTEAndSolution(); - - if (dte == null || solution == null) - { - retVal = 1; - } - else - { - MessageFilter.Register(); - - // Walk through all of the projects in the solution - // and list the type of each project. - foreach (DictionaryEntry p in projectDict) - { - string project_name = (string)p.Key; - string working_dir = (string)p.Value; - if (SetProjectWorkingDir(solution, project_name, working_dir)) - { - need_save = true; - } - } - - if (config != null) - { - need_save = SetActiveConfig(config); - } - - if (startup_project != null) - { - need_save = SetStartupProject(startup_project); - } - - if (need_save) - { - if (found_open_solution == false) - { - ViaCOM.CallMethod(solution, "Close", null); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - retVal = 1; - } - finally - { - if (solution != null) - { - Marshal.ReleaseComObject(solution); - solution = null; - } - - if (dte != null) - { - Marshal.ReleaseComObject(dte); - dte = null; - } - - MessageFilter.Revoke(); - } - return retVal; - } - - public static bool parse_command_line(string[] args) - { - string options_desc = - "--solution <solution_name> : MSVC solution name. (required)\n" + - "--use_new_vs : Ignore running versions of visual studio.\n" + - "--workingdir <project> <dir> : Set working dir of a VC project.\n" + - "--config <config> : Set the active config for the solution.\n" + - "--startup <project> : Set the startup project for the solution.\n"; - - try - { - // Command line param parsing loop. - int i = 0; - for (; i < args.Length; ++i) - { - if ("--solution" == args[i]) - { - if (solution_name != null) - { - throw new ApplicationException("Found second --solution option"); - } - solution_name = args[++i]; - } - else if ("--use_new_vs" == args[i]) - { - use_new_vs = true; - } - - else if ("--workingdir" == args[i]) - { - string project_name = args[++i]; - string working_dir = args[++i]; - projectDict.Add(project_name, working_dir); - } - else if ("--config" == args[i]) - { - if (config != null) - { - throw new ApplicationException("Found second --config option"); - } - config = args[++i]; - } - else if ("--startup" == args[i]) - { - if (startup_project != null) - { - throw new ApplicationException("Found second --startup option"); - } - startup_project = args[++i]; - } - else - { - throw new ApplicationException("Found unrecognized token on command line: " + args[i]); - } - } - - if (solution_name == null) - { - throw new ApplicationException("The --solution option is required."); - } - } - catch(ApplicationException e) - { - - Console.WriteLine("Oops! " + e.Message); - Console.Write("Command line:"); - foreach (string arg in args) - { - Console.Write(" " + arg); - } - Console.Write("\n\n"); - Console.WriteLine("VSTool command line usage"); - Console.Write(options_desc); - throw e; - } - return true; - } - - public static bool GetDTEAndSolution() - { - bool found_open_solution = true; - - Console.WriteLine("Looking for existing VisualStudio instance..."); - - // Get an instance of the currently running Visual Studio .NET IDE. - // dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.7.1"); - string full_solution_name = System.IO.Path.GetFullPath(solution_name); - if (false == use_new_vs) - { - dte = GetIDEInstance(full_solution_name); - } - - if (dte == null) - { - try - { - Console.WriteLine(" Didn't find open solution, starting new background VisualStudio instance..."); - Console.WriteLine(" Reading .sln file version..."); - string version = GetSolutionVersion(full_solution_name); - - Console.WriteLine(" Using version: {0}...", version); - string progid = GetVSProgID(version); - - Type objType = Type.GetTypeFromProgID(progid); - dte = System.Activator.CreateInstance(objType); - Console.WriteLine(" Reading solution: \"{0}\"", full_solution_name); - - solution = ViaCOM.GetProperty(dte, "Solution"); - object[] openArgs = { full_solution_name }; - ViaCOM.CallMethod(solution, "Open", openArgs); - } - catch (Exception e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Quitting do to error opening: {0}", full_solution_name); - solution = null; - dte = null; - return found_open_solution; - } - found_open_solution = false; - } - - if (solution == null) - { - solution = ViaCOM.GetProperty(dte, "Solution"); - } - - return found_open_solution; - } - - /// <summary> - /// Get the DTE object for the instance of Visual Studio IDE that has - /// the specified solution open. - /// </summary> - /// <param name="solutionFile">The absolute filename of the solution</param> - /// <returns>Corresponding DTE object or null if no such IDE is running</returns> - public static object GetIDEInstance( string solutionFile ) - { - Hashtable runningInstances = GetIDEInstances( true ); - IDictionaryEnumerator enumerator = runningInstances.GetEnumerator(); - - while ( enumerator.MoveNext() ) - { - try - { - object ide = enumerator.Value; - if (ide != null) - { - object sol = ViaCOM.GetProperty(ide, "Solution"); - if (0 == string.Compare((string)ViaCOM.GetProperty(sol, "FullName"), solutionFile, ignore_case)) - { - return ide; - } - } - } - catch{} - } - - return null; - } - - /// <summary> - /// Get a table of the currently running instances of the Visual Studio .NET IDE. - /// </summary> - /// <param name="openSolutionsOnly">Only return instances that have opened a solution</param> - /// <returns>A hashtable mapping the name of the IDE in the running object table to the corresponding DTE object</returns> - public static Hashtable GetIDEInstances( bool openSolutionsOnly ) - { - Hashtable runningIDEInstances = new Hashtable(); - Hashtable runningObjects = GetRunningObjectTable(); - - IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator(); - while ( rotEnumerator.MoveNext() ) - { - string candidateName = (string) rotEnumerator.Key; - if (!candidateName.StartsWith("!VisualStudio.DTE")) - continue; - - object ide = rotEnumerator.Value; - if (ide == null) - continue; - - if (openSolutionsOnly) - { - try - { - object sol = ViaCOM.GetProperty(ide, "Solution"); - string solutionFile = (string)ViaCOM.GetProperty(sol, "FullName"); - if (solutionFile != String.Empty) - { - runningIDEInstances[ candidateName ] = ide; - } - } - catch {} - } - else - { - runningIDEInstances[ candidateName ] = ide; - } - } - return runningIDEInstances; - } - - /// <summary> - /// Get a snapshot of the running object table (ROT). - /// </summary> - /// <returns>A hashtable mapping the name of the object in the ROT to the corresponding object</returns> - [STAThread] - public static Hashtable GetRunningObjectTable() - { - Hashtable result = new Hashtable(); - - int numFetched = 0; - IRunningObjectTable runningObjectTable; - IEnumMoniker monikerEnumerator; - IMoniker[] monikers = new IMoniker[1]; - - GetRunningObjectTable(0, out runningObjectTable); - runningObjectTable.EnumRunning(out monikerEnumerator); - monikerEnumerator.Reset(); - - while (monikerEnumerator.Next(1, monikers, new IntPtr(numFetched)) == 0) - { - IBindCtx ctx; - CreateBindCtx(0, out ctx); - - string runningObjectName; - monikers[0].GetDisplayName(ctx, null, out runningObjectName); - - object runningObjectVal; - runningObjectTable.GetObject( monikers[0], out runningObjectVal); - - result[ runningObjectName ] = runningObjectVal; - } - - return result; - } - - public static string GetSolutionVersion(string solutionFullFileName) - { - string version; - System.IO.StreamReader solutionStreamReader = null; - string firstLine; - string format; - - try - { - solutionStreamReader = new System.IO.StreamReader(solutionFullFileName); - do - { - firstLine = solutionStreamReader.ReadLine(); - } - while (firstLine == ""); - - format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim(); - - switch(format) - { - case "7.00": - version = "VC70"; - break; - - case "8.00": - version = "VC71"; - break; - - case "9.00": - version = "VC80"; - break; - - case "10.00": - version = "VC90"; - break; - default: - throw new ApplicationException("Unknown .sln version: " + format); - } - } - finally - { - if(solutionStreamReader != null) - { - solutionStreamReader.Close(); - } - } - - return version; - } - - public static string GetVSProgID(string version) - { - string progid = null; - switch(version) - { - case "VC70": - progid = "VisualStudio.DTE.7"; - break; - - case "VC71": - progid = "VisualStudio.DTE.7.1"; - break; - - case "VC80": - progid = "VisualStudio.DTE.8.0"; - break; - - case "VC90": - progid = "VisualStudio.DTE.9.0"; - break; - default: - throw new ApplicationException("Can't handle VS version: " + version); - } - - return progid; - } - - public static bool SetProjectWorkingDir(object sol, string project_name, string working_dir) - { - bool made_change = false; - Console.WriteLine("Looking for project {0}...", project_name); - try - { - object prjs = ViaCOM.GetProperty(sol, "Projects"); - object count = ViaCOM.GetProperty(prjs, "Count"); - for(int i = 1; i <= (int)count; ++i) - { - object[] prjItemArgs = { (object)i }; - object prj = ViaCOM.CallMethod(prjs, "Item", prjItemArgs); - string name = (string)ViaCOM.GetProperty(prj, "Name"); - if (0 == string.Compare(name, project_name, ignore_case)) - { - Console.WriteLine("Found project: {0}", project_name); - Console.WriteLine("Setting working directory"); - - string full_project_name = (string)ViaCOM.GetProperty(prj, "FullName"); - Console.WriteLine(full_project_name); - - // *NOTE:Mani Thanks to incompatibilities between different versions of the - // VCProjectEngine.dll assembly, we can't cast the objects recevied from the DTE to - // the VCProjectEngine types from a different version than the one built - // with. ie, VisualStudio.DTE.7.1 objects can't be converted in a project built - // in VS 8.0. To avoid this problem, we can use the com object interfaces directly, - // without the type casting. Its tedious code, but it seems to work. - - // oCfgs should be assigned to a 'Project.Configurations' collection. - object oCfgs = ViaCOM.GetProperty(ViaCOM.GetProperty(prj, "Object"), "Configurations"); - - // oCount will be assigned to the number of configs present in oCfgs. - object oCount = ViaCOM.GetProperty(oCfgs, "Count"); - - for (int cfgIndex = 1; cfgIndex <= (int)oCount; ++cfgIndex) - { - object[] itemArgs = {(object)cfgIndex}; - object oCfg = ViaCOM.CallMethod(oCfgs, "Item", itemArgs); - object oDebugSettings = ViaCOM.GetProperty(oCfg, "DebugSettings"); - ViaCOM.SetProperty(oDebugSettings, "WorkingDirectory", (object)working_dir); - } - - break; - } - } - made_change = true; - } - catch( Exception e ) - { - Console.WriteLine(e.Message); - Console.WriteLine("Failed to set working dir for project, {0}.", project_name); - } - - return made_change; - } - - public static bool SetStartupProject(string startup_project) - { - bool result = false; - try - { - // You need the 'unique name of the project to set StartupProjects. - // find the project by generic name. - Console.WriteLine("Trying to set \"{0}\" to the startup project", startup_project); - object prjs = ViaCOM.GetProperty(solution, "Projects"); - object count = ViaCOM.GetProperty(prjs, "Count"); - for (int i = 1; i <= (int)count; ++i) - { - object[] itemArgs = { (object)i }; - object prj = ViaCOM.CallMethod(prjs, "Item", itemArgs); - object prjName = ViaCOM.GetProperty(prj, "Name"); - if (0 == string.Compare((string)prjName, startup_project, ignore_case)) - { - object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); - ViaCOM.SetProperty(solBuild, "StartupProjects", ViaCOM.GetProperty(prj, "UniqueName")); - Console.WriteLine(" Success!"); - result = true; - break; - } - } - - if (result == false) - { - Console.WriteLine(" Could not find project \"{0}\" in the solution.", startup_project); - } - } - catch (Exception e) - { - Console.WriteLine(" Failed to set the startup project!"); - Console.WriteLine(e.Message); - } - return result; - } - - public static bool SetActiveConfig(string config) - { - bool result = false; - try - { - Console.WriteLine("Trying to set active config to \"{0}\"", config); - object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); - object solCfgs = ViaCOM.GetProperty(solBuild, "SolutionConfigurations"); - object[] itemArgs = { (object)config }; - object solCfg = ViaCOM.CallMethod(solCfgs, "Item", itemArgs); - ViaCOM.CallMethod(solCfg, "Activate", null); - Console.WriteLine(" Success!"); - result = true; - } - catch (Exception e) - { - Console.WriteLine(" Failed to set \"{0}\" as the active config.", config); - Console.WriteLine(e.Message); - } - return result; - } - } -} +// Code about getting running instances visual studio +// was borrowed from +// http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Microsoft.CSharp; + +namespace VSTool +{ + // The MessageFilter class comes from: + // http://msdn.microsoft.com/en-us/library/ms228772(VS.80).aspx + // It allows vstool to get timing error messages from + // visualstudio and handle them. + public class MessageFilter : IOleMessageFilter + { + // + // Class containing the IOleMessageFilter + // thread error-handling functions. + + // Start the filter. + public static void Register() + { + IOleMessageFilter newFilter = new MessageFilter(); + IOleMessageFilter oldFilter = null; + CoRegisterMessageFilter(newFilter, out oldFilter); + } + + // Done with the filter, close it. + public static void Revoke() + { + IOleMessageFilter oldFilter = null; + CoRegisterMessageFilter(null, out oldFilter); + } + + // + // IOleMessageFilter functions. + // Handle incoming thread requests. + int IOleMessageFilter.HandleInComingCall(int dwCallType, + System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr + lpInterfaceInfo) + { + //Return the flag SERVERCALL_ISHANDLED. + return 0; + } + + // Thread call was rejected, so try again. + int IOleMessageFilter.RetryRejectedCall(System.IntPtr + hTaskCallee, int dwTickCount, int dwRejectType) + { + if (dwRejectType == 2) + // flag = SERVERCALL_RETRYLATER. + { + // Retry the thread call immediately if return >=0 & + // <100. + return 99; + } + // Too busy; cancel call. + return -1; + } + + int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, + int dwTickCount, int dwPendingType) + { + //Return the flag PENDINGMSG_WAITDEFPROCESS. + return 2; + } + + // Implement the IOleMessageFilter interface. + [DllImport("Ole32.dll")] + private static extern int + CoRegisterMessageFilter(IOleMessageFilter newFilter, out + IOleMessageFilter oldFilter); + } + + [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + interface IOleMessageFilter + { + [PreserveSig] + int HandleInComingCall( + int dwCallType, + IntPtr hTaskCaller, + int dwTickCount, + IntPtr lpInterfaceInfo); + + [PreserveSig] + int RetryRejectedCall( + IntPtr hTaskCallee, + int dwTickCount, + int dwRejectType); + + [PreserveSig] + int MessagePending( + IntPtr hTaskCallee, + int dwTickCount, + int dwPendingType); + } + + class ViaCOM + { + public static object GetProperty(object from_obj, string prop_name) + { + try + { + Type objType = from_obj.GetType(); + return objType.InvokeMember( + prop_name, + BindingFlags.GetProperty, null, + from_obj, + null); + } + catch (Exception e) + { + Console.WriteLine("Error getting property: \"{0}\"", prop_name); + Console.WriteLine(e.Message); + throw e; + } + } + + public static object SetProperty(object from_obj, string prop_name, object new_value) + { + try + { + object[] args = { new_value }; + Type objType = from_obj.GetType(); + return objType.InvokeMember( + prop_name, + BindingFlags.DeclaredOnly | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.SetProperty, + null, + from_obj, + args); + } + catch (Exception e) + { + Console.WriteLine("Error setting property: \"{0}\"", prop_name); + Console.WriteLine(e.Message); + throw e; + } + } + + public static object CallMethod(object from_obj, string method_name, params object[] args) + { + try + { + Type objType = from_obj.GetType(); + return objType.InvokeMember( + method_name, + BindingFlags.DeclaredOnly | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.InvokeMethod, + null, + from_obj, + args); + } + catch (Exception e) + { + Console.WriteLine("Error calling method \"{0}\"", method_name); + Console.WriteLine(e.Message); + throw e; + } + } + }; + + /// <summary> + /// The main entry point class for VSTool. + /// </summary> + class VSToolMain + { + #region Interop imports + [DllImport("ole32.dll")] + public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); + + [DllImport("ole32.dll")] + public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); + #endregion + + static System.Boolean ignore_case = true; + + static string solution_name = null; + static bool use_new_vs = false; + static Hashtable projectDict = new Hashtable(); + static string startup_project = null; + static string config = null; + + static object dte = null; + static object solution = null; + + /// <summary> + /// The main entry point for the application. + /// </summary> + [STAThread] + static int Main(string[] args) + { + int retVal = 0; + bool need_save = false; + + try + { + parse_command_line(args); + + Console.WriteLine("Editing solution: {0}", solution_name); + + bool found_open_solution = GetDTEAndSolution(); + + if (dte == null || solution == null) + { + retVal = 1; + } + else + { + MessageFilter.Register(); + + // Walk through all of the projects in the solution + // and list the type of each project. + foreach (DictionaryEntry p in projectDict) + { + string project_name = (string)p.Key; + string working_dir = (string)p.Value; + if (SetProjectWorkingDir(solution, project_name, working_dir)) + { + need_save = true; + } + } + + if (config != null) + { + need_save = SetActiveConfig(config); + } + + if (startup_project != null) + { + need_save = SetStartupProject(startup_project); + } + + if (need_save) + { + if (found_open_solution == false) + { + ViaCOM.CallMethod(solution, "Close", null); + } + } + } + } + catch (Exception e) + { + Console.WriteLine(e.Message); + retVal = 1; + } + finally + { + if (solution != null) + { + Marshal.ReleaseComObject(solution); + solution = null; + } + + if (dte != null) + { + Marshal.ReleaseComObject(dte); + dte = null; + } + + MessageFilter.Revoke(); + } + return retVal; + } + + public static bool parse_command_line(string[] args) + { + string options_desc = + "--solution <solution_name> : MSVC solution name. (required)\n" + + "--use_new_vs : Ignore running versions of visual studio.\n" + + "--workingdir <project> <dir> : Set working dir of a VC project.\n" + + "--config <config> : Set the active config for the solution.\n" + + "--startup <project> : Set the startup project for the solution.\n"; + + try + { + // Command line param parsing loop. + int i = 0; + for (; i < args.Length; ++i) + { + if ("--solution" == args[i]) + { + if (solution_name != null) + { + throw new ApplicationException("Found second --solution option"); + } + solution_name = args[++i]; + } + else if ("--use_new_vs" == args[i]) + { + use_new_vs = true; + } + + else if ("--workingdir" == args[i]) + { + string project_name = args[++i]; + string working_dir = args[++i]; + projectDict.Add(project_name, working_dir); + } + else if ("--config" == args[i]) + { + if (config != null) + { + throw new ApplicationException("Found second --config option"); + } + config = args[++i]; + } + else if ("--startup" == args[i]) + { + if (startup_project != null) + { + throw new ApplicationException("Found second --startup option"); + } + startup_project = args[++i]; + } + else + { + throw new ApplicationException("Found unrecognized token on command line: " + args[i]); + } + } + + if (solution_name == null) + { + throw new ApplicationException("The --solution option is required."); + } + } + catch(ApplicationException e) + { + + Console.WriteLine("Oops! " + e.Message); + Console.Write("Command line:"); + foreach (string arg in args) + { + Console.Write(" " + arg); + } + Console.Write("\n\n"); + Console.WriteLine("VSTool command line usage"); + Console.Write(options_desc); + throw e; + } + return true; + } + + public static bool GetDTEAndSolution() + { + bool found_open_solution = true; + + Console.WriteLine("Looking for existing VisualStudio instance..."); + + // Get an instance of the currently running Visual Studio .NET IDE. + // dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.7.1"); + string full_solution_name = System.IO.Path.GetFullPath(solution_name); + if (false == use_new_vs) + { + dte = GetIDEInstance(full_solution_name); + } + + if (dte == null) + { + try + { + Console.WriteLine(" Didn't find open solution, starting new background VisualStudio instance..."); + Console.WriteLine(" Reading .sln file version..."); + string version = GetSolutionVersion(full_solution_name); + + Console.WriteLine(" Using version: {0}...", version); + string progid = GetVSProgID(version); + + Type objType = Type.GetTypeFromProgID(progid); + dte = System.Activator.CreateInstance(objType); + Console.WriteLine(" Reading solution: \"{0}\"", full_solution_name); + + solution = ViaCOM.GetProperty(dte, "Solution"); + object[] openArgs = { full_solution_name }; + ViaCOM.CallMethod(solution, "Open", openArgs); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine("Quitting do to error opening: {0}", full_solution_name); + solution = null; + dte = null; + return found_open_solution; + } + found_open_solution = false; + } + + if (solution == null) + { + solution = ViaCOM.GetProperty(dte, "Solution"); + } + + return found_open_solution; + } + + /// <summary> + /// Get the DTE object for the instance of Visual Studio IDE that has + /// the specified solution open. + /// </summary> + /// <param name="solutionFile">The absolute filename of the solution</param> + /// <returns>Corresponding DTE object or null if no such IDE is running</returns> + public static object GetIDEInstance( string solutionFile ) + { + Hashtable runningInstances = GetIDEInstances( true ); + IDictionaryEnumerator enumerator = runningInstances.GetEnumerator(); + + while ( enumerator.MoveNext() ) + { + try + { + object ide = enumerator.Value; + if (ide != null) + { + object sol = ViaCOM.GetProperty(ide, "Solution"); + if (0 == string.Compare((string)ViaCOM.GetProperty(sol, "FullName"), solutionFile, ignore_case)) + { + return ide; + } + } + } + catch{} + } + + return null; + } + + /// <summary> + /// Get a table of the currently running instances of the Visual Studio .NET IDE. + /// </summary> + /// <param name="openSolutionsOnly">Only return instances that have opened a solution</param> + /// <returns>A hashtable mapping the name of the IDE in the running object table to the corresponding DTE object</returns> + public static Hashtable GetIDEInstances( bool openSolutionsOnly ) + { + Hashtable runningIDEInstances = new Hashtable(); + Hashtable runningObjects = GetRunningObjectTable(); + + IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator(); + while ( rotEnumerator.MoveNext() ) + { + string candidateName = (string) rotEnumerator.Key; + if (!candidateName.StartsWith("!VisualStudio.DTE")) + continue; + + object ide = rotEnumerator.Value; + if (ide == null) + continue; + + if (openSolutionsOnly) + { + try + { + object sol = ViaCOM.GetProperty(ide, "Solution"); + string solutionFile = (string)ViaCOM.GetProperty(sol, "FullName"); + if (solutionFile != String.Empty) + { + runningIDEInstances[ candidateName ] = ide; + } + } + catch {} + } + else + { + runningIDEInstances[ candidateName ] = ide; + } + } + return runningIDEInstances; + } + + /// <summary> + /// Get a snapshot of the running object table (ROT). + /// </summary> + /// <returns>A hashtable mapping the name of the object in the ROT to the corresponding object</returns> + [STAThread] + public static Hashtable GetRunningObjectTable() + { + Hashtable result = new Hashtable(); + + int numFetched = 0; + IRunningObjectTable runningObjectTable; + IEnumMoniker monikerEnumerator; + IMoniker[] monikers = new IMoniker[1]; + + GetRunningObjectTable(0, out runningObjectTable); + runningObjectTable.EnumRunning(out monikerEnumerator); + monikerEnumerator.Reset(); + + while (monikerEnumerator.Next(1, monikers, new IntPtr(numFetched)) == 0) + { + IBindCtx ctx; + CreateBindCtx(0, out ctx); + + string runningObjectName; + monikers[0].GetDisplayName(ctx, null, out runningObjectName); + + object runningObjectVal; + runningObjectTable.GetObject( monikers[0], out runningObjectVal); + + result[ runningObjectName ] = runningObjectVal; + } + + return result; + } + + public static string GetSolutionVersion(string solutionFullFileName) + { + string version; + System.IO.StreamReader solutionStreamReader = null; + string firstLine; + string format; + + try + { + solutionStreamReader = new System.IO.StreamReader(solutionFullFileName); + do + { + firstLine = solutionStreamReader.ReadLine(); + } + while (firstLine == ""); + + format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim(); + + switch(format) + { + case "7.00": + version = "VC70"; + break; + + case "8.00": + version = "VC71"; + break; + + case "9.00": + version = "VC80"; + break; + + case "10.00": + version = "VC90"; + break; + default: + throw new ApplicationException("Unknown .sln version: " + format); + } + } + finally + { + if(solutionStreamReader != null) + { + solutionStreamReader.Close(); + } + } + + return version; + } + + public static string GetVSProgID(string version) + { + string progid = null; + switch(version) + { + case "VC70": + progid = "VisualStudio.DTE.7"; + break; + + case "VC71": + progid = "VisualStudio.DTE.7.1"; + break; + + case "VC80": + progid = "VisualStudio.DTE.8.0"; + break; + + case "VC90": + progid = "VisualStudio.DTE.9.0"; + break; + default: + throw new ApplicationException("Can't handle VS version: " + version); + } + + return progid; + } + + public static bool SetProjectWorkingDir(object sol, string project_name, string working_dir) + { + bool made_change = false; + Console.WriteLine("Looking for project {0}...", project_name); + try + { + object prjs = ViaCOM.GetProperty(sol, "Projects"); + object count = ViaCOM.GetProperty(prjs, "Count"); + for(int i = 1; i <= (int)count; ++i) + { + object[] prjItemArgs = { (object)i }; + object prj = ViaCOM.CallMethod(prjs, "Item", prjItemArgs); + string name = (string)ViaCOM.GetProperty(prj, "Name"); + if (0 == string.Compare(name, project_name, ignore_case)) + { + Console.WriteLine("Found project: {0}", project_name); + Console.WriteLine("Setting working directory"); + + string full_project_name = (string)ViaCOM.GetProperty(prj, "FullName"); + Console.WriteLine(full_project_name); + + // *NOTE:Mani Thanks to incompatibilities between different versions of the + // VCProjectEngine.dll assembly, we can't cast the objects recevied from the DTE to + // the VCProjectEngine types from a different version than the one built + // with. ie, VisualStudio.DTE.7.1 objects can't be converted in a project built + // in VS 8.0. To avoid this problem, we can use the com object interfaces directly, + // without the type casting. Its tedious code, but it seems to work. + + // oCfgs should be assigned to a 'Project.Configurations' collection. + object oCfgs = ViaCOM.GetProperty(ViaCOM.GetProperty(prj, "Object"), "Configurations"); + + // oCount will be assigned to the number of configs present in oCfgs. + object oCount = ViaCOM.GetProperty(oCfgs, "Count"); + + for (int cfgIndex = 1; cfgIndex <= (int)oCount; ++cfgIndex) + { + object[] itemArgs = {(object)cfgIndex}; + object oCfg = ViaCOM.CallMethod(oCfgs, "Item", itemArgs); + object oDebugSettings = ViaCOM.GetProperty(oCfg, "DebugSettings"); + ViaCOM.SetProperty(oDebugSettings, "WorkingDirectory", (object)working_dir); + } + + break; + } + } + made_change = true; + } + catch( Exception e ) + { + Console.WriteLine(e.Message); + Console.WriteLine("Failed to set working dir for project, {0}.", project_name); + } + + return made_change; + } + + public static bool SetStartupProject(string startup_project) + { + bool result = false; + try + { + // You need the 'unique name of the project to set StartupProjects. + // find the project by generic name. + Console.WriteLine("Trying to set \"{0}\" to the startup project", startup_project); + object prjs = ViaCOM.GetProperty(solution, "Projects"); + object count = ViaCOM.GetProperty(prjs, "Count"); + for (int i = 1; i <= (int)count; ++i) + { + object[] itemArgs = { (object)i }; + object prj = ViaCOM.CallMethod(prjs, "Item", itemArgs); + object prjName = ViaCOM.GetProperty(prj, "Name"); + if (0 == string.Compare((string)prjName, startup_project, ignore_case)) + { + object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); + ViaCOM.SetProperty(solBuild, "StartupProjects", ViaCOM.GetProperty(prj, "UniqueName")); + Console.WriteLine(" Success!"); + result = true; + break; + } + } + + if (result == false) + { + Console.WriteLine(" Could not find project \"{0}\" in the solution.", startup_project); + } + } + catch (Exception e) + { + Console.WriteLine(" Failed to set the startup project!"); + Console.WriteLine(e.Message); + } + return result; + } + + public static bool SetActiveConfig(string config) + { + bool result = false; + try + { + Console.WriteLine("Trying to set active config to \"{0}\"", config); + object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); + object solCfgs = ViaCOM.GetProperty(solBuild, "SolutionConfigurations"); + object[] itemArgs = { (object)config }; + object solCfg = ViaCOM.CallMethod(solCfgs, "Item", itemArgs); + ViaCOM.CallMethod(solCfg, "Activate", null); + Console.WriteLine(" Success!"); + result = true; + } + catch (Exception e) + { + Console.WriteLine(" Failed to set \"{0}\" as the active config.", config); + Console.WriteLine(e.Message); + } + return result; + } + } +}