diff options
102 files changed, 14118 insertions, 10850 deletions
diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py index 17bce6f434..fff78ecbe3 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 0d6f18c5d4..50129b4526 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 0898aeec47..a1fcd2cf8d 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 33705cd2b1..3c760e4d91 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 6c5fa5af6d..141b0df43c 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 671f2a4d1c..5a86b90bff 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 64e5cb5da7..192d79b27d 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 905d736d62..45b84ea3ea 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 09f19532b7..1c6f64dd8b 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 5952a3a7c5..677fad3034 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 48baa50edb..48244480b1 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 3cb074257b..6558df70a4 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 b84b1aa6ad..9f857f0fd3 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 edbb007f61..31e70e0fe4 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 fb6d5b2905..de927de1cd 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/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0133d2222d..e138b431c5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -251,7 +251,9 @@ set(viewer_SOURCE_FILES llinventorybridge.cpp llinventoryclipboard.cpp llinventoryfilter.cpp + llinventoryfunctions.cpp llinventorymodel.cpp + llinventorypanel.cpp llinventorysubtreepanel.cpp lljoystickbutton.cpp lllandmarkactions.cpp @@ -313,7 +315,6 @@ set(viewer_SOURCE_FILES llpanelgroupnotices.cpp llpanelgrouproles.cpp llpanelimcontrolpanel.cpp - llpanelinventory.cpp llpanelland.cpp llpanellandaudio.cpp llpanellandmarks.cpp @@ -321,12 +322,14 @@ set(viewer_SOURCE_FILES llpanellogin.cpp llpanellookinfo.cpp llpanellooks.cpp + llpanelmaininventory.cpp llpanelmedia.cpp llpanelmediasettingsgeneral.cpp llpanelmediasettingspermissions.cpp llpanelmediasettingssecurity.cpp llpanelmeprofile.cpp llpanelobject.cpp + llpanelobjectinventory.cpp llpanelpeople.cpp llpanelpeoplemenus.cpp llpanelpermissions.cpp @@ -366,6 +369,8 @@ set(viewer_SOURCE_FILES llsearchcombobox.cpp llsearchhistory.cpp llselectmgr.cpp + llsidepanelinventory.cpp + llsidepanelobjectinfo.cpp llsidetray.cpp llsidetraypanelcontainer.cpp llsky.cpp @@ -731,7 +736,9 @@ set(viewer_HEADER_FILES llinventorybridge.h llinventoryclipboard.h llinventoryfilter.h + llinventoryfunctions.h llinventorymodel.h + llinventorypanel.h llinventorysubtreepanel.h lljoystickbutton.h lllandmarkactions.h @@ -791,7 +798,6 @@ set(viewer_HEADER_FILES llpanelgroupnotices.h llpanelgrouproles.h llpanelimcontrolpanel.h - llpanelinventory.h llpanelland.h llpanellandaudio.h llpanellandmarks.h @@ -799,12 +805,14 @@ set(viewer_HEADER_FILES llpanellogin.h llpanellookinfo.h llpanellooks.h + llpanelmaininventory.h llpanelmedia.h llpanelmediasettingsgeneral.h llpanelmediasettingspermissions.h llpanelmediasettingssecurity.h llpanelmeprofile.h llpanelobject.h + llpanelobjectinventory.h llpanelpeople.h llpanelpeoplemenus.h llpanelpermissions.h @@ -846,6 +854,8 @@ set(viewer_HEADER_FILES llsearchcombobox.h llsearchhistory.h llselectmgr.h + llsidepanelinventory.h + llsidepanelobjectinfo.h llsidetray.h llsidetraypanelcontainer.h llsky.h diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml index 669235af1b..ab18febccc 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 185c0180fb..30f9349111 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/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 380469f5b3..4b3d27767c 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -39,6 +39,7 @@ #include "llfloaterinventory.h" #include "llinventorybridge.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "llnotify.h" #include "llviewerregion.h" #include "llvoavatarself.h" @@ -2014,7 +2015,8 @@ void LLInitialWearablesFetch::done() LLFindWearables is_wearable; gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array, LLInventoryModel::EXCLUDE_TRASH, is_wearable); - + + LLAppearanceManager::setAttachmentInvLinkEnable(true); if (wearable_array.count() > 0) { LLAppearanceManager::instance().updateAppearanceFromCOF(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 4e022aeb29..8d0f11e021 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -296,15 +296,28 @@ struct LLWearableHoldingPattern bool append; }; +/* static */ void removeDuplicateItems(LLInventoryModel::item_array_t& items) +{ + LLInventoryModel::item_array_t new_items; + std::set<LLUUID> items_seen; + for (S32 i=0; i<items.count(); i++) + { + LLViewerInventoryItem *item = items.get(i); + LLUUID item_id = item->getLinkedUUID(); + if (items_seen.find(item_id)!=items_seen.end()) + continue; + items_seen.insert(item_id); + new_items.push_back(item); + } + items = new_items; +} void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src) { LLInventoryModel::item_array_t new_dst; std::set<LLUUID> mark_inventory; - std::set<LLUUID> mark_asset; S32 inventory_dups = 0; - S32 asset_dups = 0; for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin(); src_pos != src.end(); @@ -312,8 +325,6 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory { LLUUID src_item_id = (*src_pos)->getLinkedUUID(); mark_inventory.insert(src_item_id); - LLUUID src_asset_id = (*src_pos)->getAssetUUID(); - mark_asset.insert(src_asset_id); } for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin(); @@ -324,32 +335,21 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory if (mark_inventory.find(dst_item_id) == mark_inventory.end()) { - } - else - { - inventory_dups++; - } - - LLUUID dst_asset_id = (*dst_pos)->getAssetUUID(); - - if (mark_asset.find(dst_asset_id) == mark_asset.end()) - { // Item is not already present in COF. new_dst.put(*dst_pos); - mark_asset.insert(dst_item_id); + mark_inventory.insert(dst_item_id); } else { - asset_dups++; + inventory_dups++; } } llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count() - << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl; + << " inventory dups " << inventory_dups << llendl; dst = new_dst; } - /* static */ LLUUID LLAppearanceManager::getCOF() { @@ -363,6 +363,9 @@ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, boo if (!proceed) return; +#if 1 + updateCOF(category,append); +#else if (append) { updateCOFFromCategory(category, append); // append is true - add non-duplicates to COF. @@ -380,6 +383,7 @@ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, boo rebuildCOFFromOutfit(category); } } +#endif } // Append to current COF contents by recursively traversing a folder. @@ -520,6 +524,130 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID } } } +/* static */ void LLAppearanceManager::purgeCategory(const LLUUID& category, bool keep_outfit_links) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.count(); ++i) + { + LLViewerInventoryItem *item = items.get(i); + if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) + continue; + gInventory.purgeObject(item->getUUID()); + } +} + +// Keep the last N wearables of each type. For viewer 2.0, N is 1 for +// both body parts and clothing items. +/* static */ void LLAppearanceManager::filterWearableItems( + LLInventoryModel::item_array_t& items, S32 max_per_type) +{ + // Divvy items into arrays by wearable type. + std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT); + for (S32 i=0; i<items.count(); i++) + { + LLViewerInventoryItem *item = items.get(i); + // Ignore non-wearables. + if (!item->isWearableType()) + continue; + EWearableType type = item->getWearableType(); + items_by_type[type].push_back(item); + } + + // rebuild items list, retaining the last max_per_type of each array + items.clear(); + for (S32 i=0; i<WT_COUNT; i++) + { + S32 size = items_by_type[i].size(); + if (size <= 0) + continue; + S32 start_index = llmax(0,size-max_per_type); + for (S32 j = start_index; j<size; j++) + { + items.push_back(items_by_type[i][j]); + } + } +} + +// Create links to all listed items. +/* static */ void LLAppearanceManager::linkAll(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLPointer<LLInventoryCallback> cb) +{ + for (S32 i=0; i<items.count(); i++) + { + const LLInventoryItem* item = items.get(i).get(); + link_inventory_item(gAgent.getID(), + item->getLinkedUUID(), + category, + item->getName(), + LLAssetType::AT_LINK, + cb); + } +} + +/* static */ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append) +{ + const LLUUID cof = getCOF(); + + // Collect and filter descendents to determine new COF contents. + + // - Body parts: always include COF contents as a fallback in case any + // required parts are missing. + LLInventoryModel::item_array_t body_items; + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); + getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); + // Reduce body items to max of one per type. + removeDuplicateItems(body_items); + filterWearableItems(body_items, 1); + + // - Wearables: include COF contents only if appending. + LLInventoryModel::item_array_t wear_items; + if (append) + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); + // Reduce wearables to max of one per type. + removeDuplicateItems(wear_items); + filterWearableItems(wear_items, 1); + + // - Attachments: include COF contents only if appending. + LLInventoryModel::item_array_t obj_items; + if (append) + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); + removeDuplicateItems(obj_items); + + // - Gestures: include COF contents only if appending. + LLInventoryModel::item_array_t gest_items; + if (append) + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); + removeDuplicateItems(gest_items); + + // Remove current COF contents. + bool keep_outfit_links = append; + purgeCategory(cof, keep_outfit_links); + gInventory.notifyObservers(); + + // Create links to new COF contents. + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; + + linkAll(cof, body_items, link_waiter); + linkAll(cof, wear_items, link_waiter); + linkAll(cof, obj_items, link_waiter); + linkAll(cof, gest_items, link_waiter); + + // Add link to outfit if category is an outfit. + LLViewerInventoryCategory* catp = gInventory.getCategory(category); + if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT) + { + link_inventory_item(gAgent.getID(), category, cof, catp->getName(), + LLAssetType::AT_LINK_FOLDER, link_waiter); + } + +} /* static */ bool LLAppearanceManager::isMandatoryWearableType(EWearableType type) @@ -792,6 +920,22 @@ void LLAppearanceManager::getCOFValidDescendents(const LLUUID& category, follow_folder_links); } +/* static */ +void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLAssetType::EType type, + bool follow_folder_links) +{ + LLInventoryModel::cat_array_t cats; + LLIsType is_of_type(type); + gInventory.collectDescendentsIf(category, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_of_type, + follow_folder_links); +} + /* static */ void LLAppearanceManager::getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, @@ -998,14 +1142,16 @@ void LLAppearanceManager::removeItemLinks(const LLUUID& item_id, bool do_update) } } +//#define DUMP_CAT_VERBOSE + /* static */ -void LLAppearanceManager::dumpCat(const LLUUID& cat_id, std::string str) +void LLAppearanceManager::dumpCat(const LLUUID& cat_id, const std::string& msg) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); -#if 0 +#ifdef DUMP_CAT_VERBOSE llinfos << llendl; llinfos << str << llendl; S32 hitcount = 0; @@ -1017,6 +1163,89 @@ void LLAppearanceManager::dumpCat(const LLUUID& cat_id, std::string str) llinfos << i <<" "<< item->getName() <<llendl; } #endif - llinfos << str << " count " << items.count() << llendl; + llinfos << msg << " count " << items.count() << llendl; } +/* static */ +void LLAppearanceManager::dumpItemArray(const LLInventoryModel::item_array_t& items, + const std::string& msg) +{ + llinfos << msg << llendl; + for (S32 i=0; i<items.count(); i++) + { + LLViewerInventoryItem *item = items.get(i); + llinfos << i <<" " << item->getName() << llendl; + } + llinfos << llendl; +} + + +std::set<LLUUID> LLAppearanceManager::sRegisteredAttachments; +bool LLAppearanceManager::sAttachmentInvLinkEnabled(false); + +/* static */ +void LLAppearanceManager::setAttachmentInvLinkEnable(bool val) +{ + llinfos << "setAttachmentInvLinkEnable => " << (int) val << llendl; + sAttachmentInvLinkEnabled = val; +} + +void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg) +{ + llinfos << msg << llendl; + for (std::set<LLUUID>::const_iterator it = atts.begin(); + it != atts.end(); + ++it) + { + LLUUID item_id = *it; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item) + llinfos << "atts " << item->getName() << llendl; + else + llinfos << "atts " << "UNKNOWN[" << item_id.asString() << "]" << llendl; + } + llinfos << llendl; +} + +/* static */ +void LLAppearanceManager::registerAttachment(const LLUUID& item_id) +{ + sRegisteredAttachments.insert(item_id); + dumpAttachmentSet(sRegisteredAttachments,"after register:"); + + if (sAttachmentInvLinkEnabled) + { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item) + { + LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Adding attachment link:"); + LLAppearanceManager::wearItem(item,false); // Add COF link for item. + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + } + else + { + llinfos << "no link changes, inv link not enabled" << llendl; + } +} + +/* static */ +void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id) +{ + sRegisteredAttachments.erase(item_id); + dumpAttachmentSet(sRegisteredAttachments,"after unregister:"); + + if (sAttachmentInvLinkEnabled) + { + LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Removing attachment link:"); + LLAppearanceManager::removeItemLinks(item_id, false); + // BAP - needs to change for label to track link. + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + else + { + llinfos << "no link changes, inv link not enabled" << llendl; + } +} diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 828af32101..56f54dfc23 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -46,6 +46,7 @@ public: static void updateAppearanceFromCOF(); static bool needToSaveCOF(); static void changeOutfit(bool proceed, const LLUUID& category, bool append); + static void updateCOF(const LLUUID& category, bool append = false); static void updateCOFFromCategory(const LLUUID& category, bool append); static void rebuildCOFFromOutfit(const LLUUID& category); static void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -65,9 +66,23 @@ public: static void removeItemLinks(const LLUUID& item_id, bool do_update = true); // For debugging - could be moved elsewhere. - static void dumpCat(const LLUUID& cat_id, std::string str); + static void dumpCat(const LLUUID& cat_id, const std::string& msg); + static void dumpItemArray(const LLInventoryModel::item_array_t& items, const std::string& msg); + static void unregisterAttachment(const LLUUID& item_id); + static void registerAttachment(const LLUUID& item_id); + static void setAttachmentInvLinkEnable(bool val); private: + static void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type); + static void linkAll(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLPointer<LLInventoryCallback> cb); + + static void getDescendentsOfAssetType(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLAssetType::EType type, + bool follow_folder_links); + static void getCOFValidDescendents(const LLUUID& category, LLInventoryModel::item_array_t& items); @@ -81,6 +96,11 @@ private: static bool isMandatoryWearableType(EWearableType type); static void checkMandatoryWearableTypes(const LLUUID& category, std::set<EWearableType>& types_found); static void purgeCOFBeforeRebuild(const LLUUID& category); + static void purgeCategory(const LLUUID& category, bool keep_outfit_links); + + static std::set<LLUUID> sRegisteredAttachments; + static bool sAttachmentInvLinkEnabled; + }; #define SUPPORT_ENSEMBLES 0 diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index cd3963050f..5dbf57c9be 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -41,6 +41,7 @@ #include "llfilepicker.h" #include "llnotify.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "llfloaterinventory.h" #include "llpermissionsflags.h" #include "llpreviewnotecard.h" diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 88658f7b9f..b01293d17c 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/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 9d07362edc..3da06fa7b3 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -45,6 +45,7 @@ #include "llinventorymodel.h" // for gInventory #include "llfloaterreg.h" #include "llfloaterinventory.h" // for get_item_icon +#include "llinventoryfunctions.h" #include "llselectmgr.h" #include "llscrolllistctrl.h" #include "llviewerobject.h" diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index 3a4171c6be..f3eaa0c916 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -45,6 +45,7 @@ #include "llagent.h" // for agent id #include "llalertdialog.h" #include "llcheckboxctrl.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" // for gInventory #include "llfloaterreg.h" #include "llfloaterinventory.h" // for get_item_icon @@ -280,7 +281,7 @@ void LLFloaterBuyContents::onClickBuy() // We may want to wear this item if (childGetValue("wear_check")) { - LLFloaterInventory::sWearNewClothing = TRUE; + LLInventoryState::sWearNewClothing = TRUE; } // Put the items where we put new folders. diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 1300103423..c114eed4a2 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -44,6 +44,7 @@ #include "llcombobox.h" #include "llgesturemgr.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "llfloaterinventory.h" #include "llkeyboard.h" #include "lllineeditor.h" diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index a47916b7d7..8570b5eb4a 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -32,539 +32,34 @@ #include "llviewerprecompiledheaders.h" -#include <utility> // for std::pair<> - #include "llfloaterinventory.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 "llfloaterreg.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 "llpanelmaininventory.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"); - -//BOOL LLFloaterInventory::sOpenNextNewItem = FALSE; -BOOL LLFloaterInventory::sWearNewClothing = FALSE; -LLUUID LLFloaterInventory::sWearNewClothingTransactionID; - -///---------------------------------------------------------------------------- -/// LLFloaterInventoryFinder -///---------------------------------------------------------------------------- - -LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLFloaterInventory* inventory_view) -: LLFloater(LLSD()), - mFloaterInventory(inventory_view), - mFilter(inventory_view->mActivePanel->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 = mFloaterInventory->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 - LLFloater::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 - mFloaterInventory->mActivePanel->setShowFolderState(getCheckShowEmpty() ? - LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mFloaterInventory->mActivePanel->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; - mFloaterInventory->mActivePanel->setHoursAgo(hours); - mFloaterInventory->mActivePanel->setSinceLogoff(getCheckSinceLogoff()); - mFloaterInventory->setFilterTextFromFilter(); - - LLFloater::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); - -/* - self->mCheckCallingCard->set(TRUE); - self->mCheckClothing->set(TRUE); - self->mCheckGesture->set(TRUE); - self->mCheckLandmark->set(TRUE); - self->mCheckNotecard->set(TRUE); - self->mCheckObject->set(TRUE); - self->mCheckScript->set(TRUE); - self->mCheckSound->set(TRUE); - self->mCheckTexture->set(TRUE); - self->mCheckSnapshot->set(TRUE);*/ -} - -//static -void LLFloaterInventoryFinder::selectNoTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - /* - self->childSetValue("check_animation", FALSE); - self->mCheckCallingCard->set(FALSE); - self->mCheckClothing->set(FALSE); - self->mCheckGesture->set(FALSE); - self->mCheckLandmark->set(FALSE); - self->mCheckNotecard->set(FALSE); - self->mCheckObject->set(FALSE); - self->mCheckScript->set(FALSE); - self->mCheckSound->set(FALSE); - self->mCheckTexture->set(FALSE); - self->mCheckSnapshot->set(FALSE);*/ - - - 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); -} - ///---------------------------------------------------------------------------- /// LLFloaterInventory ///---------------------------------------------------------------------------- -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()); - } - } -} LLFloaterInventory::LLFloaterInventory(const LLSD& key) : LLFloater(key) { - LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_INIT); - // Menu Callbacks (non contex menus) - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLFloaterInventory::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLFloaterInventory::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(&LLFloaterInventory::doCreate, this, _2)); -// mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLFloaterInventory::newWindow, this)); - mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLFloaterInventory::toggleFindOptions, this)); - mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLFloaterInventory::resetFilters, this)); - mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLFloaterInventory::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); +} - //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory.xml"); +LLFloaterInventory::~LLFloaterInventory() +{ } BOOL LLFloaterInventory::postBuild() { - gInventory.addObserver(this); - - mFilterTabs = getChild<LLTabContainer>("inventory filter tabs"); - mFilterTabs->setCommitCallback(boost::bind(&LLFloaterInventory::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 << "LLFloaterInventory::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(&LLFloaterInventory::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); - + mPanelMainInventory = getChild<LLPanelMainInventory>("Inventory Panel"); return TRUE; } -// Destroys the object -LLFloaterInventory::~LLFloaterInventory( 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(); - 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(); - 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 LLFloaterInventory::draw() { @@ -575,113 +70,6 @@ void LLFloaterInventory::draw() LLFloater::draw(); } -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); - } -} - -void LLFloaterInventory::startSearch() -{ - // this forces focus to line editor portion of search editor - if (mFilterEditor) - { - mFilterEditor->focusFirstItem(TRUE); - } -} - -void LLFloaterInventory::onOpen(const LLSD& key) -{ - LLFirstUse::useInventory(); -} - -BOOL LLFloaterInventory::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 LLFloater::handleKeyHere(key, mask); - -} - void LLFloaterInventory::updateTitle() { LLLocale locale(LLLocale::USER_LOCALE); @@ -690,7 +78,7 @@ void LLFloaterInventory::updateTitle() LLStringUtil::format_map_t string_args; string_args["[ITEM_COUNT]"] = item_count_string; - string_args["[FILTER]"] = mFilterText; + string_args["[FILTER]"] = mPanelMainInventory->getFilterText(); if (LLInventoryModel::backgroundFetchActive()) { @@ -699,102 +87,21 @@ void LLFloaterInventory::updateTitle() else { setTitle(getString("TitleCompleted", string_args)); - } + } } - void LLFloaterInventory::changed(U32 mask) { updateTitle(); } -//---------------------------------------------------------------------------- -// menu callbacks - -void LLFloaterInventory::doToSelected(const LLSD& userdata) -{ - getPanel()->getRootFolder()->doToSelected(&gInventory, userdata); -} - -void LLFloaterInventory::closeAllFolders() -{ - getPanel()->getRootFolder()->closeAllFolders(); -} - -void LLFloaterInventory::doCreate(const LLSD& userdata) -{ - menu_create_inventory_item(getPanel()->getRootFolder(), NULL, userdata); -} - -void LLFloaterInventory::resetFilters() -{ - LLFloaterInventoryFinder *finder = getFinder(); - getActivePanel()->getFilter()->resetDefault(); - if (finder) - { - finder->updateElementsFromFilter(); - } - - setFilterTextFromFilter(); -} - -void LLFloaterInventory::setSortBy(const LLSD& userdata) +LLInventoryPanel* LLFloaterInventory::getPanel() { - 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 ); - } + if (mPanelMainInventory) + return mPanelMainInventory->getPanel(); + return NULL; } -//---------------------------------------------------------------------------- - // static LLFloaterInventory* LLFloaterInventory::showAgentInventory() { @@ -842,1112 +149,7 @@ void LLFloaterInventory::cleanup() } } -void LLFloaterInventory::toggleFindOptions() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE); - LLFloater *floater = getFinder(); - if (!floater) - { - LLFloaterInventoryFinder * finder = new LLFloaterInventoryFinder(this); - mFinderHandle = finder->getHandle(); - finder->openFloater(); - addDependentFloater(mFinderHandle); - - // start background fetch of folders - gInventory.startBackgroundFetch(); - } - else - { - floater->closeFloater(); - } -} - -// static -BOOL LLFloaterInventory::filtersVisible(void* user_data) -{ - LLFloaterInventory* self = (LLFloaterInventory*)user_data; - if(!self) return FALSE; - - return self->getFinder() != NULL; -} - -void LLFloaterInventory::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 LLFloaterInventory::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 LLFloaterInventory::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) - { - LLFloaterInventory* 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) - { - LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*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->mActivePanel && - active_view->mActivePanel->getRootFolder()->search(first_item, search_string, backward)) - { - return TRUE; - } - - return FALSE; - } - -void LLFloaterInventory::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(); -} - -BOOL LLFloaterInventory::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 = LLFloater::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - - return handled; -} -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); -} - -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(); -} - -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() +void LLFloaterInventory::onOpen(const LLSD& key) { - 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); + LLFirstUse::useInventory(); } diff --git a/indra/newview/llfloaterinventory.h b/indra/newview/llfloaterinventory.h index 4c9ac5d4c6..f2f2963a33 100644 --- a/indra/newview/llfloaterinventory.h +++ b/indra/newview/llfloaterinventory.h @@ -31,366 +31,54 @@ * $/LicenseInfo$ */ -#ifndef LL_LLINVENTORYVIEW_H -#define LL_LLINVENTORYVIEW_H +#ifndef LL_LLFLOATERINVENTORY_H +#define LL_LLFLOATERINVENTORY_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 LLInventoryPanel; +class LLPanelMainInventory; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFloaterInventory // -// This is the agent inventory _floater_. -// It deals with the buttons and views used to navigate as -// well as controls the behavior of the overall object. +// This deals with the buttons and views used to navigate as +// well as controlling the behavior of the overall object. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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 +class LLFloaterInventory : public LLFloater { 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() { return mFolders->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; - -}; - -class LLFloaterInventory; - -class LLFloaterInventoryFinder : public LLFloater -{ -public: - LLFloaterInventoryFinder( LLFloaterInventory* 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); - -protected: - LLFloaterInventory* mFloaterInventory; - LLSpinCtrl* mSpinSinceDays; - LLSpinCtrl* mSpinSinceHours; - LLInventoryFilter* mFilter; -}; - -class LLFloaterInventory : public LLFloater, LLInventoryObserver -{ -friend class LLFloaterInventoryFinder; - -public: LLFloaterInventory(const LLSD& key); ~LLFloaterInventory(); - /*virtual*/ void changed(U32 mask); - - BOOL postBuild(); - - // - // Misc functions - // - void setFilterTextFromFilter() { mFilterText = mActivePanel->getFilter()->getFilterText(); } - void startSearch(); - - // This method makes sure that an inventory view exists, is - // visible, and has focus. The view chosen is returned. - static LLFloaterInventory* showAgentInventory(); + BOOL postBuild(); // Return the active inventory view if there is one. Active is // defined as the inventory that is the closest to the front, and // is visible. static LLFloaterInventory* getActiveInventory(); - // This method calls showAgentInventory() if no views are visible, - // or hides/destroyes them all if any are visible. - static void toggleVisibility(); - static void toggleVisibility(void*) { toggleVisibility(); } + // This method makes sure that an inventory view exists, is + // visible, and has focus. The view chosen is returned. + static LLFloaterInventory* showAgentInventory(); // Final cleanup, destroy all open inventory views. static void cleanup(); - // LLView & LLFloater functionality - virtual void onOpen(const LLSD& key); - virtual void draw(); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - - LLInventoryPanel* getPanel() { return mActivePanel; } - LLInventoryPanel* getActivePanel() { return mActivePanel; } - - 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() { return mActivePanel->getFilterSubString(); } - void setFilterSubString(const std::string& string) { mActivePanel->setFilterSubString(string); } - - // menu callbacks - void doToSelected(const LLSD& userdata); - void closeAllFolders(); - void doCreate(const LLSD& userdata); - void resetFilters(); - void setSortBy(const LLSD& userdata); - - // HACK: Until we can route this info through the instant message hierarchy - static BOOL sWearNewClothing; - static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction - - void toggleFindOptions(); - - LLFloaterInventoryFinder* getFinder() { return (LLFloaterInventoryFinder*)mFinderHandle.get(); } + // Inherited functionality + /*virtual*/ void changed(U32 mask); + /*virtual*/ void draw(); + /*virtual*/ void onOpen(const LLSD& key); + LLInventoryPanel* getPanel(); protected: - LLFilterEditor* mFilterEditor; - LLTabContainer* mFilterTabs; - LLHandle<LLFloater> mFinderHandle; - LLInventoryPanel* mActivePanel; - LLSaveFolderState* mSavedFolderState; - - std::string mFilterText; - -private: void updateTitle(); +private: + LLPanelMainInventory* mPanelMainInventory; }; -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); -}; - -///---------------------------------------------------------------------------- -/// Function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - -// useful functions with the inventory view - -class LLInventoryCategory; -class LLInventoryItem; - -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_LLINVENTORYVIEW_H +#endif // LL_LLFLOATERINVENTORY_H diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index aa82dc34b7..b6ec0868cf 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -32,7 +32,7 @@ /* * Shows the contents of an object. - * A floater wrapper for llpanelinventory + * A floater wrapper for LLPanelObjectInventory */ #include "llviewerprecompiledheaders.h" @@ -47,7 +47,8 @@ #include "llinventorybridge.h" #include "llfloaterinventory.h" #include "llinventorymodel.h" -#include "llpanelinventory.h" +#include "llinventorypanel.h" +#include "llpanelobjectinventory.h" #include "llfloaterreg.h" #include "llselectmgr.h" #include "lluiconstants.h" @@ -58,7 +59,7 @@ LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key) : LLFloater(key), - mPanelInventory(NULL), + mPanelInventoryObject(NULL), mDirty(TRUE) { // LLUICtrlFactory::getInstance()->buildFloater(this,"floater_openobject.xml"); @@ -74,7 +75,7 @@ LLFloaterOpenObject::~LLFloaterOpenObject() BOOL LLFloaterOpenObject::postBuild() { childSetTextArg("object_name", "[DESC]", std::string("Object") ); // *Note: probably do not want to translate this - mPanelInventory = getChild<LLPanelInventory>("object_contents"); + mPanelInventoryObject = getChild<LLPanelObjectInventory>("object_contents"); return TRUE; } @@ -96,7 +97,7 @@ void LLFloaterOpenObject::onOpen(const LLSD& key) } void LLFloaterOpenObject::refresh() { - mPanelInventory->refresh(); + mPanelInventoryObject->refresh(); std::string name; BOOL enabled; diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index a61cc04941..10d96b7ea3 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -41,7 +41,7 @@ #include "llfloater.h" class LLObjectSelection; -class LLPanelInventory; +class LLPanelObjectInventory; class LLFloaterOpenObject : public LLFloater @@ -77,7 +77,7 @@ private: protected: - LLPanelInventory* mPanelInventory; + LLPanelObjectInventory* mPanelInventoryObject; LLSafeHandle<LLObjectSelection> mObjectSelection; BOOL mDirty; }; diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 5fee84190b..3aef15a35c 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -54,7 +54,7 @@ #include "llpanelcontents.h" #include "llpanelface.h" #include "llpanelland.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llpanelobject.h" #include "llpanelvolume.h" #include "llpanelpermissions.h" diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index de18e74752..a963c96da4 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -38,6 +38,7 @@ #include "llinventorybridge.h" #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryfilter.h" +#include "llinventoryfunctions.h" #include "llfoldertype.h" #include "llfloaterinventory.h"// hacked in for the bonus context menu items. #include "llkeyboard.h" diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index c4beb666ea..7399f1e1b3 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -70,6 +70,7 @@ #include "llpanelimcontrolpanel.h" #include "llrecentpeople.h" #include "llresmgr.h" +#include "lltooldraganddrop.h" #include "lltrans.h" #include "lltabcontainer.h" #include "llviewertexteditor.h" diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 59f70ea1bd..b9775cf0e9 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -62,7 +62,9 @@ #include "llavataractions.h" #include "llgesturemgr.h" #include "lliconctrl.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "llinventoryclipboard.h" #include "lllineeditor.h" #include "llmenugl.h" @@ -275,7 +277,11 @@ void LLInvFVBridge::cutToClipboard() // *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { - LLFloaterReg::showInstance("properties", mUUID); + LLSD key; + key["id"] = mUUID; + LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); + + // LLFloaterReg::showInstance("properties", mUUID); } void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) @@ -506,7 +512,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const return TRUE; } -void hideContextEntries(LLMenuGL& menu, +void hide_context_entries(LLMenuGL& menu, const std::vector<std::string> &entries_to_show, const std::vector<std::string> &disabled_entries) { @@ -521,7 +527,7 @@ void hideContextEntries(LLMenuGL& menu, LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(*itor); if ((name == "More") && branchp) { - hideContextEntries(*branchp->getBranch(), entries_to_show, disabled_entries); + hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries); } @@ -598,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) @@ -621,7 +633,7 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) getClipboardEntries(true, items, disabled_items, flags); } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } // *TODO: remove this @@ -2387,7 +2399,7 @@ void LLFolderBridge::folderOptionsMenu() } mItems.push_back(std::string("Take Off Items")); } - hideContextEntries(*mMenu, mItems, disabled_items); + hide_context_entries(*mMenu, mItems, disabled_items); } BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) @@ -2526,7 +2538,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mItems.push_back(std::string("--no options--")); mDisabledItems.push_back(std::string("--no options--")); } - hideContextEntries(menu, mItems, mDisabledItems); + hide_context_entries(menu, mItems, mDisabledItems); } BOOL LLFolderBridge::hasChildren() const @@ -3147,7 +3159,7 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Sound Separator")); items.push_back(std::string("Sound Play")); - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } // +=================================================+ @@ -3204,7 +3216,7 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("About Landmark")); } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } // Convenience function for the two functions below. @@ -3433,7 +3445,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Conference Chat")); } } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, @@ -3662,7 +3674,7 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Activate")); items.push_back(std::string("Deactivate")); } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } // +=================================================+ @@ -3702,7 +3714,7 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Animation Play")); items.push_back(std::string("Animation Audition")); - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } @@ -3847,6 +3859,10 @@ void LLObjectBridge::openItem() LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } + LLSD key; + key["id"] = mUUID; + LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); + /* LLFloaterReg::showInstance("properties", mUUID); */ @@ -4058,7 +4074,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } } } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } BOOL LLObjectBridge::renameItem(const std::string& new_name) @@ -4471,7 +4487,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } } } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } // Called from menus @@ -5043,7 +5059,7 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Delete")); } } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } @@ -5094,7 +5110,7 @@ void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Delete")); } } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } void LLLinkFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 6b2a2d32de..3f3513a665 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -41,6 +41,7 @@ #include "llfoldervieweventlistener.h" class LLInventoryPanel; +class LLMenuGL; enum EInventoryIcon { @@ -121,7 +122,7 @@ protected: }; const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type); -void hideContextEntries(LLMenuGL& menu, +void hide_context_entries(LLMenuGL& menu, const std::vector<std::string> &entries_to_show, const std::vector<std::string> &disabled_entries); @@ -807,5 +808,9 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, void teleport_via_landmark(const LLUUID& asset_id); +// Utility function to hide all entries except those in the list +void hide_context_entries(LLMenuGL& menu, + const std::vector<std::string> &entries_to_show, + const std::vector<std::string> &disabled_entries); #endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp new file mode 100644 index 0000000000..77121bd922 --- /dev/null +++ b/indra/newview/llinventoryfunctions.cpp @@ -0,0 +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); +} diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h new file mode 100644 index 0000000000..95cc68ddbe --- /dev/null +++ b/indra/newview/llinventoryfunctions.h @@ -0,0 +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 + + + diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 1d7cbde0d5..23439191f3 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -46,6 +46,8 @@ #include "llfloater.h" #include "llfocusmgr.h" #include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" #include "llfloaterinventory.h" #include "llviewerinventory.h" #include "llviewermessage.h" @@ -3174,13 +3176,13 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // The incoming inventory could span more than one BulkInventoryUpdate packet, // so record the transaction ID for this purchase, then wear all clothing // that comes in as part of that transaction ID. JC - if (LLFloaterInventory::sWearNewClothing) + if (LLInventoryState::sWearNewClothing) { - LLFloaterInventory::sWearNewClothingTransactionID = tid; - LLFloaterInventory::sWearNewClothing = FALSE; + LLInventoryState::sWearNewClothingTransactionID = tid; + LLInventoryState::sWearNewClothing = FALSE; } - if (tid == LLFloaterInventory::sWearNewClothingTransactionID) + if (tid == LLInventoryState::sWearNewClothingTransactionID) { count = wearable_ids.size(); for (i = 0; i < count; ++i) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp new file mode 100644 index 0000000000..d1ca0efed3 --- /dev/null +++ b/indra/newview/llinventorypanel.cpp @@ -0,0 +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); +} diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h new file mode 100644 index 0000000000..997678a478 --- /dev/null +++ b/indra/newview/llinventorypanel.h @@ -0,0 +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 diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index ea528a1df8..c28792a711 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -51,7 +51,7 @@ // project includes #include "llagent.h" #include "llfloaterbulkpermission.h" -#include "llpanelinventory.h" +#include "llpanelobjectinventory.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -89,14 +89,14 @@ BOOL LLPanelContents::postBuild() childSetAction("button new script",&LLPanelContents::onClickNewScript, this); childSetAction("button permissions",&LLPanelContents::onClickPermissions, this); - mPanelInventory = getChild<LLPanelInventory>("contents_inventory"); + mPanelInventoryObject = getChild<LLPanelObjectInventory>("contents_inventory"); return TRUE; } LLPanelContents::LLPanelContents() : LLPanel(), - mPanelInventory(NULL) + mPanelInventoryObject(NULL) { } @@ -139,9 +139,9 @@ void LLPanelContents::refresh() LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); getState(object); - if (mPanelInventory) + if (mPanelInventoryObject) { - mPanelInventory->refresh(); + mPanelInventoryObject->refresh(); } } diff --git a/indra/newview/llpanelcontents.h b/indra/newview/llpanelcontents.h index bab980b524..14256845a6 100644 --- a/indra/newview/llpanelcontents.h +++ b/indra/newview/llpanelcontents.h @@ -35,9 +35,14 @@ #include "v3math.h" #include "llpanel.h" +#include "llinventory.h" +#include "lluuid.h" +#include "llmap.h" +#include "llviewerobject.h" +#include "llvoinventorylistener.h" class LLButton; -class LLPanelInventory; +class LLPanelObjectInventory; class LLViewerObject; class LLCheckBoxCtrl; class LLSpinCtrl; @@ -70,7 +75,7 @@ protected: void getState(LLViewerObject *object); public: - LLPanelInventory* mPanelInventory; + LLPanelObjectInventory* mPanelInventoryObject; }; -#endif +#endif // LL_LLPANELCONTENTS_H diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 0ce85818dd..22138a81ec 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -38,6 +38,7 @@ #include "llinventory.h" #include "llviewerinventory.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llfloaterinventory.h" #include "llagent.h" diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index c9598a2576..91e1590dc3 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -47,6 +47,7 @@ #include "lldndbutton.h" #include "llfloaterworldmap.h" #include "llfolderviewitem.h" +#include "llinventorypanel.h" #include "llinventorysubtreepanel.h" #include "lllandmarkactions.h" #include "llplacesinventorybridge.h" diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp new file mode 100644 index 0000000000..617445a27f --- /dev/null +++ b/indra/newview/llpanelmaininventory.cpp @@ -0,0 +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); +} diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h new file mode 100644 index 0000000000..a2b988e80c --- /dev/null +++ b/indra/newview/llpanelmaininventory.h @@ -0,0 +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 + + + diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index a198499b47..85efe0f93e 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 33f0952f53..3577f63340 100644 --- a/indra/newview/llpanelmediasettingssecurity.cpp +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -235,17 +235,17 @@ void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) 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() )
- {
+ 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;
- };
-
- // 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 *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;
@@ -332,10 +332,10 @@ void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) self->mWhiteListList->deleteSelectedItems();
}
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent )
-{
- mParent = parent;
-};
-
+//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent ) +{ + mParent = parent; +}; + diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h index b78ee92193..2555bb8dc8 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/llpanelobject.h b/indra/newview/llpanelobject.h index 1ab4ff581e..58d9fe9b76 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -45,7 +45,6 @@ class LLUICtrl; class LLButton; class LLViewerObject; class LLComboBox; -class LLPanelInventory; class LLColorSwatchCtrl; class LLTextureCtrl; class LLInventoryItem; diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp new file mode 100644 index 0000000000..68181f12b9 --- /dev/null +++ b/indra/newview/llpanelobjectinventory.cpp @@ -0,0 +1,1927 @@ +/** + * @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) + { + if(item->getParentUUID().isNull()) + { + if(item->getName() == "Contents") + { + mDisplayName.assign(LLTrans::getString("ViewerObjectContents")); + } + else + { + mDisplayName.assign(item->getName()); + } + } + else + { + 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(LLTrans::getString("no_copy")); + } + if(!mod) + { + mDisplayName.append(LLTrans::getString("no_modify")); + } + if(!xfer) + { + mDisplayName.append(LLTrans::getString("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 new file mode 100644 index 0000000000..6722bb212e --- /dev/null +++ b/indra/newview/llpanelobjectinventory.h @@ -0,0 +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 diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 4ac109bf3d..5a70842a73 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -57,7 +57,6 @@ #include "llfirstuse.h" #include "llfocusmgr.h" #include "llmanipscale.h" -#include "llpanelinventory.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 9d197aafa5..7bc935f986 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -45,7 +45,6 @@ class LLUICtrl; class LLButton; class LLViewerObject; class LLComboBox; -class LLPanelInventory; class LLColorSwatchCtrl; class LLPanelVolume : public LLPanel diff --git a/indra/newview/llplacesinventorybridge.cpp b/indra/newview/llplacesinventorybridge.cpp index b3b4857727..83443687c9 100644 --- a/indra/newview/llplacesinventorybridge.cpp +++ b/indra/newview/llplacesinventorybridge.cpp @@ -38,6 +38,7 @@ #include "llfloaterinventory.h" // for LLInventoryPanel #include "llfolderview.h" // for FIRST_SELECTED_ITEM +#include "llinventorypanel.h" static const std::string LANDMARKS_INVENTORY_LIST_NAME("landmarks_list"); @@ -83,7 +84,7 @@ void LLPlacesLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // they should be synchronized with Places/My Landmarks/Gear menu. See EXT-1601 } - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } @@ -116,7 +117,7 @@ void LLPlacesFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // repeat parent functionality sSelf = this; // necessary for "New Folder" functionality - hideContextEntries(menu, items, disabled_items); + hide_context_entries(menu, items, disabled_items); } } diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index b391c6ff1d..2382befcfa 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -89,7 +89,6 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llappviewer.h" -#include "llpanelinventory.h" const std::string HELLO_LSL = "default\n" diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp new file mode 100644 index 0000000000..3cf17fb7f2 --- /dev/null +++ b/indra/newview/llsidepanelinventory.cpp @@ -0,0 +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) +{ + + //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 new file mode 100644 index 0000000000..62eeecc5e2 --- /dev/null +++ b/indra/newview/llsidepanelinventory.h @@ -0,0 +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); + +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/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 4940d9b5bb..50ebc205a9 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -47,7 +47,9 @@ #include "llfolderview.h" #include "llfoldervieweventlistener.h" #include "llinventory.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "llfloaterinventory.h" #include "lllineeditor.h" #include "llui.h" diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index e26a0776ff..e78737fe0d 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -38,6 +38,7 @@ #include "llbutton.h" #include "lliconctrl.h" +#include "llinventoryfunctions.h" #include "llnotify.h" #include "lltextbox.h" diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 366e5602bd..470739baa9 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -38,6 +38,7 @@ #include "llagent.h" #include "llfoldertype.h" +#include "llfolderview.h" #include "llviewercontrol.h" #include "llconsole.h" #include "llinventorymodel.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9da9ff5ce7..23ceb1e72d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -50,6 +50,7 @@ #include "llfocusmgr.h" #include "llfontgl.h" #include "llinstantmessage.h" +#include "llinventorypanel.h" #include "llpermissionsflags.h" #include "llrect.h" #include "llsecondlifeurls.h" diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5fd762ab3d..ff1c7b526f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -89,6 +89,7 @@ #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llinventorymodel.h" +#include "llinventorypanel.h" #include "llfloaterinventory.h" #include "llmenugl.h" #include "llmoveview.h" diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 758db538a2..a964f43171 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1080,15 +1080,8 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view if (attachment->isObjectAttached(viewer_object)) { const LLUUID& attachment_id = viewer_object->getItemID(); - LLViewerInventoryItem *item = gInventory.getItem(attachment_id); - if (item) - { - LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Adding attachment link:"); - LLAppearanceManager::wearItem(item,false); // Add COF link for item. - gInventory.addChangedMask(LLInventoryObserver::LABEL, attachment_id); - } + LLAppearanceManager::registerAttachment(attachment_id); } - gInventory.notifyObservers(); return attachment; } @@ -1096,12 +1089,12 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view //virtual BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) { - const LLUUID item_id = viewer_object->getItemID(); + const LLUUID attachment_id = viewer_object->getItemID(); if (LLVOAvatar::detachObject(viewer_object)) { // the simulator should automatically handle permission revocation - stopMotionFromSource(item_id); + stopMotionFromSource(attachment_id); LLFollowCamMgr::setCameraActive(viewer_object->getID(), FALSE); LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); @@ -1126,13 +1119,9 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) } else { - LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Removing attachment link:"); - LLAppearanceManager::removeItemLinks(item_id, false); + LLAppearanceManager::unregisterAttachment(attachment_id); } - // BAP - needs to change for label to track link. - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - gInventory.notifyObservers(); return TRUE; } return FALSE; diff --git a/indra/newview/skins/default/html/da/loading/loading.html b/indra/newview/skins/default/html/da/loading/loading.html index cdad5702b9..5f3426eb60 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 3eddbc24f5..44a621b216 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 34e5c84c4d..1c62d2f73e 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 f03284ba8c..c4260b34c0 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 23c0ef03bc..b3953448e9 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 ade91f76c2..ab15a073ba 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 0f9af31f6e..ab37e41f04 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 069dc5d12f..35cf74a35f 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 39a8691f3f..0215bd7e47 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 515890c2d5..50f3dfb0c5 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 635ea62406..a83e1123d0 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 dcc0d73c1a..892c0b9f7f 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 e7812e7c8e..1ac07bff34 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 0f67994635..3b5b8679b4 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 462ea291d9..d1d5d25c92 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/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a75d38d967..4aafe462b7 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -396,6 +396,10 @@ <texture name="TabIcon_Home_Off" file_name="taskpanel/TabIcon_Home_Off.png" preload="false" /> <texture name="TabIcon_Home_Over" file_name="taskpanel/TabIcon_Home_Over.png" preload="false" /> <texture name="TabIcon_Home_Selected" file_name="taskpanel/TabIcon_Home_Selected.png" preload="false" /> + <texture name="TabIcon_Inventory_Large" file_name="taskpanel/TabIcon_Inventory_Large.png" preload="false" /> + <texture name="TabIcon_Inventory_Off" file_name="taskpanel/TabIcon_Inventory_Off.png" preload="false" /> + <texture name="TabIcon_Inventory_Over" file_name="taskpanel/TabIcon_Inventory_Over.png" preload="false" /> + <texture name="TabIcon_Inventory_Selected" file_name="taskpanel/TabIcon_Inventory_Selected.png" preload="false" /> <texture name="TabIcon_Me_Large" file_name="taskpanel/TabIcon_Me_Large.png" preload="false" /> <texture name="TabIcon_Me_Off" file_name="taskpanel/TabIcon_Me_Off.png" preload="false" /> <texture name="TabIcon_Me_Over" file_name="taskpanel/TabIcon_Me_Over.png" preload="false" /> 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 74b7c7dd72..b4d0fa20ef 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 1f67e0231d..3203eacdb5 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 dfa6c83b4e..3e19bdee0f 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -30,405 +30,16 @@ name="Fetched"> Fetched </floater.string> - <filter_editor - search_button_visible="false" - text_pad_left="12" - follows="left|top|right" - height="16" - label="Type here to search" - layout="topleft" - left="6" - name="inventory search editor" - top="34" - width="455" /> - <tab_container - follows="all" - height="508" - halign="center" - layout="topleft" - left_delta="-4" - name="inventory filter tabs" - tab_position="top" - tab_height="20" - top_pad="5" - width="463"> - <inventory_panel - follows="left|top|right|bottom" - height="491" - label="All Items" - layout="topleft" - left="1" - name="All Items" - top="16" - width="461" /> - <inventory_panel - follows="left|top|right|bottom" - height="491" - label="Recent Items" - layout="topleft" - left_delta="0" - name="Recent Items" - top_delta="0" - width="461" /> - </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="-38" - width="461"> - <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 + 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/floater_openobject.xml b/indra/newview/skins/default/xui/en/floater_openobject.xml index cc50f43339..af8aadf0e0 100644 --- a/indra/newview/skins/default/xui/en/floater_openobject.xml +++ b/indra/newview/skins/default/xui/en/floater_openobject.xml @@ -26,7 +26,7 @@ width="284"> [DESC]: </text> - <panel_inventory + <panel_inventory_object background_visible="false" draw_border="false" follows="all" diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index f566dbdb75..fc736211de 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2793,7 +2793,7 @@ left_pad="8" name="button permissions" width="130" /> - <panel_inventory + <panel_inventory_object follows="left|top" height="210" layout="topleft" 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 240822e5ca..19c2bf3496 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 new file mode 100644 index 0000000000..9a3fdcc327 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -0,0 +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> 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 3f64c9c633..3582de1c71 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml @@ -128,4 +128,23 @@ /> </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/panel_sidetray_home_tab.xml b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml index 247054772e..9636e32187 100644 --- a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml +++ b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml @@ -12,7 +12,7 @@ bg_alpha_color="DkGray2" class="panel_sidetray_home_info" follows="left|top|right" - height="120" + height="90" layout="topleft" left="15" top="17" @@ -42,7 +42,7 @@ width="20" /> <text follows="left|right|bottom" - height="120" + height="90" layout="topleft" left="10" mouse_opaque="false" @@ -59,7 +59,7 @@ bg_alpha_color="DkGray2" class="panel_sidetray_home_info" follows="left|top|right" - height="120" + height="90" layout="topleft" left="15" top_pad="15" @@ -89,7 +89,7 @@ image_name="TabIcon_Places_Selected"/> <text follows="all" - height="120" + height="90" layout="topleft" left="10" mouse_opaque="false" @@ -106,7 +106,7 @@ bg_alpha_color="DkGray2" class="panel_sidetray_home_info" follows="left|top|right" - height="120" + height="90" layout="topleft" left="15" top_pad="15" @@ -136,7 +136,7 @@ image_name="TabIcon_Me_Selected"/> <text follows="all" - height="120" + height="90" layout="topleft" left="10" mouse_opaque="false" @@ -153,7 +153,7 @@ bg_alpha_color="DkGray2" class="panel_sidetray_home_info" follows="left|top|right" - height="120" + height="90" layout="topleft" left="15" top_pad="15" @@ -183,7 +183,7 @@ image_name="TabIcon_Appearance_Selected"/> <text follows="all" - height="120" + height="90" layout="topleft" left="10" mouse_opaque="false" @@ -195,4 +195,51 @@ Change your appearance and current look. </text> </panel> + <panel + background_visible="true" + bg_alpha_color="DkGray2" + class="panel_sidetray_home_info" + follows="left|top|right" + height="90" + layout="topleft" + left="15" + top_pad="15" + name="sidebar_inventory" + width="303"> + <text + follows="left|right|top" + font="SansSerifBigBold" + height="30" + layout="topleft" + left="10" + mouse_opaque="false" + name="tab_name" + text_color="EmphasisColor" + top="10" + value="My Inventory" + width="200" + word_wrap="true" /> + <icon + follows="top|right" + height="20" + layout="topleft" + name="tab_icon" + right="-10" + top="10" + width="20" + image_name="TabIcon_Inventory_Selected"/> + <text + follows="all" + height="90" + layout="topleft" + left="10" + mouse_opaque="false" + name="tab_description" + right="-10" + text_color="white" + top="40" + word_wrap="true"> + Browse your inventory. + </text> + </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml new file mode 100644 index 0000000000..d0c3cdfafc --- /dev/null +++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml @@ -0,0 +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> 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 bcf4128e01..c12dd8d58c 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 f62ea7c80f..3a1585bce2 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 0eba7bf3b6..33f3c367c2 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 ca4ab3e773..2cf8456187 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 00f8c087de..172395e20a 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 e449a92d7e..97fa3118f8 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 e97e77cfe6..a989cab167 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 009be35f64..d31a81e128 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 e419180031..6f64aa41df 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 24f1031f81..5d8764b6bf 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 8859671802..543a0a2efc 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 cc268d59d9..5c41c916e2 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; + } + } +} |