diff options
author | Steve Bennetts <steve@lindenlab.com> | 2009-10-12 13:22:58 -0700 |
---|---|---|
committer | Steve Bennetts <steve@lindenlab.com> | 2009-10-12 13:22:58 -0700 |
commit | 4a1ef20c317897e7e509c7f599e97fcc90ffaefc (patch) | |
tree | c496bd8785b94bb60bca33ea59758c5929341451 | |
parent | 895e8ad446ab383e1211f759e8b55aa0fff2efc1 (diff) | |
parent | d4b2897700c66354413af42ab055bd1aaa47f91c (diff) |
merge
304 files changed, 5857 insertions, 1737 deletions
diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000000..28c78eb994 --- /dev/null +++ b/.hgignore @@ -0,0 +1,42 @@ +syntax: glob + +*.pyc +*~ +.*.swp +LICENSES +indra/.distcc +indra/build-darwin-* +indra/build-vc[0-9]* +indra/lib/mono/1.0/*.dll +indra/lib/mono/indra/*.dll +indra/lib/mono/indra/*.exe +indra/lib/mono/indra/*.pdb +indra/llwindow/glh/glh_linear.h +indra/newview/app_settings/mozilla +indra/newview/app_settings/mozilla-runtime-* +indra/newview/app_settings/mozilla_debug +indra/newview/app_settings/static_*.db2 +indra/newview/character +indra/newview/fmod.dll +indra/newview/mozilla-theme +indra/newview/mozilla-universal-darwin.tgz +indra/newview/res-sdl +indra/newview/skins +indra/newview/vivox-runtime +indra/server-linux-* +indra/test/linden_file.dat +indra/test_apps/llmediatest/dependencies/i686-win32 +indra/test_apps/terrain_mule/*.dll +indra/viewer-linux-* +indra/web/doc/asset-upload/plugins/lsl_compiler/lslc +indra/web/doc/asset-upload/plugins/verify-notecard +indra/web/doc/asset-upload/plugins/verify-texture +installed.xml +libraries +tarfile_tmp +^web/locale.* +^web/secondlife.com.* +^web/config.* +^indra/web/dataservice/locale.* +^indra/web/dataservice/lib/shared/vault.* +^indra/web/dataservice/vendor.* diff --git a/etc/message.xml b/etc/message.xml index d2ba9843e4..da08e12aa1 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -669,11 +669,14 @@ <key>FetchLib</key> <boolean>true</boolean> - <key>ObjectMedia</key> - <boolean>false</boolean> + <key>UploadBakedTexture</key> + <boolean>true</boolean> + + <key>ObjectMedia</key> + <boolean>false</boolean> - <key>ObjectMediaNavigate</key> - <boolean>false</boolean> + <key>ObjectMediaNavigate</key> + <boolean>false</boolean> </map> diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 2a70263446..c356feb13a 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -192,13 +192,13 @@ endif (DARWIN) if (LINUX OR DARWIN) - set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual") + set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs") if (NOT GCC_DISABLE_FATAL_WARNINGS) set(GCC_WARNINGS "${GCC_WARNINGS} -Werror") endif (NOT GCC_DISABLE_FATAL_WARNINGS) - set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder") + set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual") set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}") diff --git a/indra/cmake/GoogleMock.cmake b/indra/cmake/GoogleMock.cmake new file mode 100644 index 0000000000..ca5a8034ba --- /dev/null +++ b/indra/cmake/GoogleMock.cmake @@ -0,0 +1,27 @@ +# -*- cmake -*- +include(Prebuilt) +include(Linking) + +use_prebuilt_binary(googlemock) + +set(GOOGLEMOCK_INCLUDE_DIRS + ${LIBS_PREBUILT_DIR}/include) + +if (LINUX) + set(GOOGLEMOCK_LIBRARIES + gmock + gtest) +elseif(WINDOWS) + set(GOOGLEMOCK_LIBRARIES + gmock) + set(GOOGLEMOCK_INCLUDE_DIRS + ${LIBS_PREBUILT_DIR}/include + ${LIBS_PREBUILT_DIR}/include/gmock + ${LIBS_PREBUILT_DIR}/include/gmock/boost/tr1/tr1) +elseif(DARWIN) + set(GOOGLEMOCK_LIBRARIES + gmock + gtest) +endif(LINUX) + + diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 7d6ef9ab1a..373ad4d4e9 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -13,6 +13,8 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) # # WARNING: do NOT modify this code without working with poppy or daveh - # there is another branch that will conflict heavily with any changes here. +INCLUDE(GoogleMock) + IF(LL_TEST_VERBOSE) MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}") @@ -32,8 +34,10 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) ${LLMATH_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${LIBS_OPEN_DIR}/test + ${GOOGLEMOCK_INCLUDE_DIRS} ) SET(alltest_LIBRARIES + ${GOOGLEMOCK_LIBRARIES} ${PTHREAD_LIBRARY} ${WINDOWS_LIBRARIES} ) @@ -42,6 +46,11 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) ${CMAKE_SOURCE_DIR}/test/test.h ) + # Use the default flags + if (LINUX) + SET(CMAKE_EXE_LINKER_FLAGS "") + endif (LINUX) + # start the source test executable definitions SET(${project}_TEST_OUTPUT "") FOREACH (source ${sources}) @@ -84,9 +93,9 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}") ENDIF(LL_TEST_VERBOSE) + # Setup target ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES}) - # # Per-codefile additional / external project dep and lib dep property extraction # diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py index 1190d88663..4527b115f9 100644 --- a/indra/lib/python/indra/base/llsd.py +++ b/indra/lib/python/indra/base/llsd.py @@ -238,7 +238,7 @@ class LLSDXMLFormatter(object): def MAP(self, v): return self.elt( 'map', - ''.join(["%s%s" % (self.elt('key', key), self.generate(value)) + ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value)) for key, value in v.items()])) typeof = type diff --git a/indra/lib/python/indra/base/lluuid.py b/indra/lib/python/indra/base/lluuid.py index aceea29cd2..1cdd8e915b 100644 --- a/indra/lib/python/indra/base/lluuid.py +++ b/indra/lib/python/indra/base/lluuid.py @@ -26,8 +26,14 @@ THE SOFTWARE. $/LicenseInfo$ """ -import md5, random, socket, string, time, re +import random, socket, string, time, re import uuid +try: + # Python 2.6 + from hashlib import md5 +except ImportError: + # Python 2.5 and earlier + from md5 import new as md5 def _int2binstr(i,l): s='' @@ -196,7 +202,7 @@ class UUID(object): from c++ implementation for portability reasons. Returns self. """ - m = md5.new() + m = md5() m.update(uuid.uuid1().bytes) self._bits = m.digest() return self diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py index c4c40739ec..7e0e115d14 100644 --- a/indra/lib/python/indra/util/llsubprocess.py +++ b/indra/lib/python/indra/util/llsubprocess.py @@ -90,6 +90,17 @@ all the output, and get the result. child.tochild.close() result = child.poll() if result != -1: + # At this point, the child process has exited and result + # is the return value from the process. Between the time + # we called select() and poll() the process may have + # exited so read all the data left on the child process + # stdout and stderr. + last = child.fromchild.read() + if last: + out.append(last) + last = child.childerr.read() + if last: + err.append(last) child.tochild.close() child.fromchild.close() child.childerr.close() diff --git a/indra/lib/python/indra/util/llversion.py b/indra/lib/python/indra/util/llversion.py index 770b861ddc..2718a85f41 100644 --- a/indra/lib/python/indra/util/llversion.py +++ b/indra/lib/python/indra/util/llversion.py @@ -1,7 +1,7 @@ """@file llversion.py @brief Utility for parsing llcommon/llversion${server}.h for the version string and channel string - Utility that parses svn info for branch and revision + Utility that parses hg or svn info for branch and revision $LicenseInfo:firstyear=2006&license=mit$ @@ -79,8 +79,8 @@ def get_svn_status_matching(regular_expression): status, output = commands.getstatusoutput('svn info %s' % get_src_root()) m = regular_expression.search(output) if not m: - print "Failed to parse svn info output, resultfollows:" - print output + print >> sys.stderr, "Failed to parse svn info output, result follows:" + print >> sys.stderr, output raise Exception, "No matching svn status in "+src_root return m.group(1) @@ -92,4 +92,35 @@ def get_svn_revision(): last_rev_re = re.compile('Last Changed Rev: (\d+)') return get_svn_status_matching(last_rev_re) - +def get_hg_repo(): + status, output = commands.getstatusoutput('hg showconfig paths.default') + if status: + print >> sys.stderr, output + sys.exit(1) + if not output: + print >> sys.stderr, 'ERROR: cannot find repo we cloned from' + sys.exit(1) + return output + +def get_hg_changeset(): + # The right thing to do: + # status, output = commands.getstatusoutput('hg id -i') + # if status: + # print >> sys.stderr, output + # sys.exit(1) + + # The temporary hack: + status, output = commands.getstatusoutput('hg parents --template "{rev}"') + if status: + print >> sys.stderr, output + sys.exit(1) + lines = output.splitlines() + if len(lines) > 1: + print >> sys.stderr, 'ERROR: working directory has %d parents' % len(lines) + return lines[0] + +def using_svn(): + return os.path.isdir(os.path.join(get_src_root(), '.svn')) + +def using_hg(): + return os.path.isdir(os.path.join(get_src_root(), '.hg')) diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py index 693b483f79..5c19368240 100644 --- a/indra/lib/python/indra/util/named_query.py +++ b/indra/lib/python/indra/util/named_query.py @@ -48,8 +48,8 @@ from indra.base import llsd from indra.base import config DEBUG = False -NQ_FILE_SUFFIX = None -NQ_FILE_SUFFIX_LEN = None +NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') +NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX) _g_named_manager = None diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp index 1d42298f4d..1ae0ddeea0 100644 --- a/indra/llcharacter/llkeyframestandmotion.cpp +++ b/indra/llcharacter/llkeyframestandmotion.cpp @@ -190,7 +190,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD) { mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation(); - mLastGoodPelvisRotation.normQuat(); + mLastGoodPelvisRotation.normalize(); mTrackAnkles = TRUE; } else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index bc4e44d7e6..138dc85459 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -240,7 +240,7 @@ SET(llcommon_TEST_SOURCE_FILES LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}") #set(TEST_DEBUG on) -set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) +set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES}) # Have to treat lllazy test as an integration test until this issue is resolved: # https://jira.lindenlab.com/jira/browse/DEV-29456 LL_ADD_INTEGRATION_TEST(lllazy lllazy.cpp "${test_libs}") diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 5d7672b378..78aa6f4f37 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -289,6 +289,7 @@ bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type) asset_type <= AT_FOLDER_ENSEMBLE_END); } + // static. Generate a good default description void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, std::string& description) diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 5e51188541..880b7a19b5 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -150,6 +150,7 @@ public: AT_COUNT = 49, + // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | // +*********************************************************+ diff --git a/indra/llcommon/llcursortypes.cpp b/indra/llcommon/llcursortypes.cpp index 7444115aa1..23ede97af3 100644 --- a/indra/llcommon/llcursortypes.cpp +++ b/indra/llcommon/llcursortypes.cpp @@ -30,6 +30,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llcursortypes.h" ECursorType getCursorFromString(const std::string& cursor_string) @@ -66,10 +68,6 @@ ECursorType getCursorFromString(const std::string& cursor_string) cursor_string_table["UI_CURSOR_TOOLPAN"] = UI_CURSOR_TOOLPAN; cursor_string_table["UI_CURSOR_TOOLZOOMIN"] = UI_CURSOR_TOOLZOOMIN; cursor_string_table["UI_CURSOR_TOOLPICKOBJECT3"] = UI_CURSOR_TOOLPICKOBJECT3; - cursor_string_table["UI_CURSOR_TOOLSIT"] = UI_CURSOR_TOOLSIT; - cursor_string_table["UI_CURSOR_TOOLBUY"] = UI_CURSOR_TOOLBUY; - cursor_string_table["UI_CURSOR_TOOLPAY"] = UI_CURSOR_TOOLPAY; - cursor_string_table["UI_CURSOR_TOOLOPEN"] = UI_CURSOR_TOOLOPEN; cursor_string_table["UI_CURSOR_TOOLPLAY"] = UI_CURSOR_TOOLPLAY; cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE; cursor_string_table["UI_CURSOR_TOOLMEDIAOPEN"] = UI_CURSOR_TOOLMEDIAOPEN; diff --git a/indra/llcommon/llcursortypes.h b/indra/llcommon/llcursortypes.h index bea70351b7..35dbeaf16e 100644 --- a/indra/llcommon/llcursortypes.h +++ b/indra/llcommon/llcursortypes.h @@ -33,8 +33,6 @@ #ifndef LL_LLCURSORTYPES_H #define LL_LLCURSORTYPES_H -#include "linden_common.h" - // If you add types here, add them in LLCursor::getCursorFromString enum ECursorType { UI_CURSOR_ARROW, @@ -66,10 +64,6 @@ enum ECursorType { UI_CURSOR_TOOLPAN, UI_CURSOR_TOOLZOOMIN, UI_CURSOR_TOOLPICKOBJECT3, - UI_CURSOR_TOOLSIT, - UI_CURSOR_TOOLBUY, - UI_CURSOR_TOOLPAY, - UI_CURSOR_TOOLOPEN, UI_CURSOR_TOOLPLAY, UI_CURSOR_TOOLPAUSE, UI_CURSOR_TOOLMEDIAOPEN, diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 0d89353dee..c2f23f6ff6 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -114,8 +114,9 @@ public: // recursive call to gather total time from children static void accumulateTimings(); - // called once per frame by LLFastTimer - static void processFrame(); + // 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(); @@ -178,8 +179,9 @@ public: { #if FAST_TIMER_ON NamedTimer::FrameState* frame_state = mFrameState; - frame_state->mLastStartTime = get_cpu_clock_count(); - mStartSelfTime = frame_state->mLastStartTime; + U64 cur_time = get_cpu_clock_count(); + frame_state->mLastStartTime = cur_time; + mStartSelfTime = cur_time; frame_state->mActiveCount++; frame_state->mCalls++; @@ -215,6 +217,10 @@ public: // 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(); diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 873f50a65e..7544ab1d11 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -118,6 +118,63 @@ public: THROTTLE_BLOCKED, // rate exceed, block key }; + F64 getActionCount(const T& id) + { + U64 now = 0; + if ( mIsRealtime ) + { + now = LLKeyThrottleImpl<T>::getTime(); + } + else + { + now = LLKeyThrottleImpl<T>::getFrame(); + } + + if (now >= (m.startTime + m.intervalLength)) + { + if (now < (m.startTime + 2 * m.intervalLength)) + { + // prune old data + delete m.prevMap; + m.prevMap = m.currMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime += m.intervalLength; + } + else + { + // lots of time has passed, all data is stale + delete m.prevMap; + delete m.currMap; + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime = now; + } + } + + U32 prevCount = 0; + + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + } + + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + + // curr.count is the number of keys in + // this current 'time slice' from the beginning of it until now + // prevCount is the number of keys in the previous + // time slice scaled to be one full time slice back from the current + // (now) time. + + // compute current, windowed rate + F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); + F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); + return averageCount; + } + // call each time the key wants use State noteAction(const T& id, S32 weight = 1) { diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index c12ca350de..7e1c2e35e0 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -37,6 +37,7 @@ #include <deque> #include "apr_base64.h" +#include <boost/regex.hpp> extern "C" { @@ -777,10 +778,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) case ELEMENT_BINARY: { - S32 len = apr_base64_decode_len(mCurrentContent.c_str()); + // Regex is expensive, but only fix for whitespace in base64, + // created by python and other non-linden systems - DEV-39358 + // Fortunately we have very little binary passing now, + // so performance impact shold be negligible. + poppy 2009-09-04 + boost::regex r; + r.assign("\\s"); + std::string stripped = boost::regex_replace(mCurrentContent, r, ""); + S32 len = apr_base64_decode_len(stripped.c_str()); std::vector<U8> data; data.resize(len); - len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str()); + len = apr_base64_decode_binary(&data[0], stripped.c_str()); data.resize(len); value = data; break; diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 90dae11793..0bd2609f4a 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -43,7 +43,7 @@ // statics -BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information +S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step" LLStat::stat_map_t LLStat::sStatList; @@ -130,6 +130,7 @@ bool LLStatsConfigFile::loadFile() F32 duration = 0.f; F32 interval = 0.f; + S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS; const char * w = "duration"; if (stats_config.has(w)) @@ -141,8 +142,18 @@ bool LLStatsConfigFile::loadFile() { interval = (F32)stats_config[w].asReal(); } + w = "flags"; + if (stats_config.has(w)) + { + flags = (S32)stats_config[w].asInteger(); + if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS && + duration > 0) + { // No flags passed in, but have a duration, so reset to basic stats + flags = LLPerfBlock::LLSTATS_BASIC_STATS; + } + } - mStatsp->setReportPerformanceDuration( duration ); + mStatsp->setReportPerformanceDuration( duration, flags ); mStatsp->setReportPerformanceInterval( interval ); if ( duration > 0 ) @@ -254,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats() } } -// Set length of performance stat recording -void LLPerfStats::setReportPerformanceDuration( F32 seconds ) +// Set length of performance stat recording. +// If turning stats on, caller must provide flags +void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ ) { if ( seconds <= 0.f ) { mReportPerformanceStatEnd = 0.0; - LLPerfBlock::setStatsEnabled( FALSE ); + LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off mFrameStatsFile.close(); LLPerfBlock::clearDynamicStats(); } @@ -269,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds ) mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds); // Clear failure flag to try and create the log file once mFrameStatsFileFailure = FALSE; - LLPerfBlock::setStatsEnabled( TRUE ); mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame) + LLPerfBlock::setStatsFlags(flags); } } @@ -612,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta } } -// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key. -// These are also turned on or off via the switch passed in -LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL) +// Use this constructor for normal, optional LLPerfBlock time slices +LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL) { - if (!sStatsEnabled) return; + if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0) + { // These are off unless the base set is enabled + return; + } + + initDynamicStat(key); +} + + +// Use this constructor for dynamically created LLPerfBlock time slices +// that are only enabled by specific control flags +LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL) +{ + if ((sStatsFlags & flags) == 0) + { + return; + } if (NULL == key2 || strlen(key2) == 0) { @@ -630,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat } } +// Set up the result data map if dynamic stats are enabled void LLPerfBlock::initDynamicStat(const std::string& key) { // Early exit if dynamic stats aren't enabled. - if (!sStatsEnabled) return; + if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS) + return; mLastPath = sCurrentStatPath; // Save and restore current path sCurrentStatPath += "/" + key; // Add key to current path diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index bad18f46a0..76aa3963f4 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -192,14 +192,23 @@ public: // Use this constructor for pre-defined LLStatTime objects LLPerfBlock(LLStatTime* stat); - // Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key - LLPerfBlock( const char* key1, const char* key2 = NULL); + // Use this constructor for normal, optional LLPerfBlock time slices + LLPerfBlock( const char* key ); + // Use this constructor for dynamically created LLPerfBlock time slices + // that are only enabled by specific control flags + LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS ); ~LLPerfBlock(); - static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; }; - static S32 getStatsEnabled() { return sStatsEnabled; }; + enum + { // Stats bitfield flags + LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects + LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats + LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls + }; + static void setStatsFlags( S32 flags ) { sStatsFlags = flags; }; + static S32 getStatsFlags() { return sStatsFlags; }; static void clearDynamicStats(); // Reset maps to clear out dynamic objects static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin @@ -213,7 +222,7 @@ private: LLStatTime * mPredefinedStat; // LLStatTime object to get data StatEntry * mDynamicStat; // StatEntryobject to get data - static BOOL sStatsEnabled; // Normally FALSE + static S32 sStatsFlags; // Control what is being recorded static stat_map_t sStatMap; // Map full path string to LLStatTime objects static std::string sCurrentStatPath; // Something like "frame/physics/physics step" }; @@ -236,7 +245,7 @@ public: BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); }; F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; }; void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; }; - void setReportPerformanceDuration( F32 seconds ); + void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS ); void setProcessName(const std::string& process_name) { mProcessName = process_name; } void setProcessPID(S32 process_pid) { mProcessPID = process_pid; } diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h index 888361b0b9..5c4831cc2b 100644 --- a/indra/llcommon/llstringtable.h +++ b/indra/llcommon/llstringtable.h @@ -48,10 +48,12 @@ //# define STRING_TABLE_HASH_MAP 1 #endif -#if LL_WINDOWS -#include <hash_map> -#else -#include <ext/hash_map> +#if STRING_TABLE_HASH_MAP +# if LL_WINDOWS +# include <hash_map> +# else +# include <ext/hash_map> +# endif #endif const U32 MAX_STRINGS_LENGTH = 256; diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index 23e39ceb08..77a03879bf 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -34,9 +34,9 @@ #define LL_LLVERSIONSERVER_H const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 29; +const S32 LL_VERSION_MINOR = 31; const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 0; +const S32 LL_VERSION_BUILD = 2639; const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 2c3e9c7333..e69ca7eec5 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -36,7 +36,7 @@ const S32 LL_VERSION_MAJOR = 2; const S32 LL_VERSION_MINOR = 0; const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 0; +const S32 LL_VERSION_BUILD = 2639; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/metapropertyt.h b/indra/llcommon/metapropertyt.h index 79a536a224..5ad230d1d5 100644 --- a/indra/llcommon/metapropertyt.h +++ b/indra/llcommon/metapropertyt.h @@ -94,6 +94,13 @@ inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* obje } template <> +inline const LLReflective* LLMetaPropertyT<bool>::get(const LLReflective* object) const +{ + checkObjectClass(object); + return NULL; +} + +template <> inline LLSD LLMetaPropertyT<S32>::getLLSD(const LLReflective* object) const { return *(getProperty(object)); @@ -111,6 +118,12 @@ inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const return *(getProperty(object)); } +template <> +inline LLSD LLMetaPropertyT<bool>::getLLSD(const LLReflective* object) const +{ + return *(getProperty(object)); +} + template<class TObject, class TProperty> class LLMetaPropertyTT : public LLMetaPropertyT<TProperty> { diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 363486fb9c..2352c8edd7 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -178,8 +178,8 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mMaxBytes(0), mRawDiscardLevel(-1), mRate(0.0f), - mReversible(FALSE) - + mReversible(FALSE), + mAreaUsedForDataSizeCalcs(0) { //We assume here that if we wanted to create via //a dynamic library that the approriate open calls were made @@ -195,6 +195,12 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), } mImpl = j2cimpl_create_func(); + + // Clear data size table + for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++) + { // Array size is MAX_DISCARD_LEVEL+1 + mDataSizes[i] = 0; + } } // virtual @@ -367,9 +373,45 @@ S32 LLImageJ2C::calcHeaderSize() return calcHeaderSizeJ2C(); } + +// calcDataSize() returns how many bytes to read +// to load discard_level (including header and higher discard levels) S32 LLImageJ2C::calcDataSize(S32 discard_level) { - return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate); + discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); + + if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth()) + || mDataSizes[0] == 0) + { + mAreaUsedForDataSizeCalcs = getHeight() * getWidth(); + + S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard + while ( level >= 0 ) + { + mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); + level--; + } + + /* This is technically a more correct way to calculate the size required + for each discard level, since they should include the size needed for + lower levels. Unfortunately, this doesn't work well and will lead to + download stalls. The true correct way is to parse the header. This will + all go away with http textures at some point. + + // Calculate the size for each discard level. Lower levels (higher quality) + // contain the cumulative size of higher levels + S32 total_size = calcHeaderSizeJ2C(); + + S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard + while ( level >= 0 ) + { // Add in this discard level and all before it + total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); + mDataSizes[level] = total_size; + level--; + } + */ + } + return mDataSizes[discard_level]; } S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 23f6ef5fd1..55df7f4429 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -87,6 +87,10 @@ protected: void updateRawDiscardLevel(); S32 mMaxBytes; // Maximum number of bytes of data to use... + + S32 mDataSizes[MAX_DISCARD_LEVEL+1]; // Size of data required to reach a given level + U32 mAreaUsedForDataSizeCalcs; // Height * width used to calculate mDataSizes + S8 mRawDiscardLevel; F32 mRate; BOOL mReversible; diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index e2a77f1d1e..5d3fbe5128 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -458,6 +458,39 @@ void LLInventoryItem::setCreationDate(time_t creation_date_utc) mCreationDate = creation_date_utc; } +void LLInventoryItem::accumulatePermissionSlamBits(const LLInventoryItem& old_item) +{ + // Remove any pre-existing II_FLAGS_PERM_OVERWRITE_MASK flags + // because we now detect when they should be set. + setFlags( old_item.getFlags() | (getFlags() & ~(LLInventoryItem::II_FLAGS_PERM_OVERWRITE_MASK)) ); + + // Enforce the PERM_OVERWRITE flags for any masks that are different + // but only for AT_OBJECT's since that is the only asset type that can + // exist in-world (instead of only in-inventory or in-object-contents). + if (LLAssetType::AT_OBJECT == getType()) + { + LLPermissions old_permissions = old_item.getPermissions(); + U32 flags_to_be_set = 0; + if(old_permissions.getMaskNextOwner() != getPermissions().getMaskNextOwner()) + { + flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_PERM; + } + if(old_permissions.getMaskEveryone() != getPermissions().getMaskEveryone()) + { + flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE; + } + if(old_permissions.getMaskGroup() != getPermissions().getMaskGroup()) + { + flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP; + } + LLSaleInfo old_sale_info = old_item.getSaleInfo(); + if(old_sale_info != getSaleInfo()) + { + flags_to_be_set |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_SALE; + } + setFlags(getFlags() | flags_to_be_set); + } +} const LLSaleInfo& LLInventoryItem::getSaleInfo() const { diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 64af6c94f5..bd581e860f 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -93,7 +93,6 @@ public: virtual const LLUUID& getUUID() const; const LLUUID& getParentUUID() const; virtual const LLUUID& getLinkedUUID() const; // get the inventoryID that this item points to, else this item's inventoryID - virtual const std::string& getName() const; virtual LLAssetType::EType getType() const; LLAssetType::EType getActualType() const; // bypasses indirection for linked items @@ -263,6 +262,10 @@ public: void setInventoryType(LLInventoryType::EType inv_type); void setFlags(U32 flags); void setCreationDate(time_t creation_date_utc); + + // Check for changes in permissions masks and sale info + // and set the corresponding bits in mFlags + void accumulatePermissionSlamBits(const LLInventoryItem& old_item); // This is currently only used in the Viewer to handle calling cards // where the creator is actually used to store the target. diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index aa8391230c..2a9a596912 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -136,9 +136,9 @@ class LLSD; class LLAccessEntry { public: - LLUUID mID; - S32 mTime; - U32 mFlags; + LLUUID mID; // Agent ID + S32 mTime; // Time (unix seconds) when entry expires + U32 mFlags; // Not used - currently should always be zero }; typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator; diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index 0babf26457..d2e5034734 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -288,6 +288,17 @@ BOOL LLPermissions::setOwnerAndGroup( return allowed; } +//Fix for DEV-33917, last owner isn't used much and has little impact on +//permissions so it's reasonably safe to do this, however, for now, +//limiting the functionality of this routine to objects which are +//group owned. +void LLPermissions::setLastOwner(const LLUUID& last_owner) +{ + if (isGroupOwned()) + mLastOwner = last_owner; +} + + // only call this if you know what you're doing // there are usually perm-bit consequences when the // ownerhsip changes @@ -895,6 +906,8 @@ void LLMetaClassT<LLPermissions>::reflectProperties(LLMetaClass& meta_class) { reflectProperty(meta_class, "mCreator", &LLPermissions::mCreator); reflectProperty(meta_class, "mOwner", &LLPermissions::mOwner); + reflectProperty(meta_class, "mGroup", &LLPermissions::mGroup); + reflectProperty(meta_class, "mIsGroupOwned", &LLPermissions::mIsGroupOwned); } // virtual diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index 864088148f..d5a0881c8f 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -232,6 +232,10 @@ public: // ownerhsip changes void yesReallySetOwner(const LLUUID& owner, bool group_owned); + // Last owner doesn't have much in the way of permissions so it's + //not too dangerous to do this. + void setLastOwner(const LLUUID& last_owner); + // saves last owner, sets owner to uuid null, sets group // owned. group_id must be the group of the object (that's who it // is being deeded to) and the object must be group diff --git a/indra/llinventory/lltransactiontypes.h b/indra/llinventory/lltransactiontypes.h index 1cb7308bd4..2c699bcb87 100644 --- a/indra/llinventory/lltransactiontypes.h +++ b/indra/llinventory/lltransactiontypes.h @@ -69,6 +69,12 @@ const S32 TRANS_PARCEL_DIR_FEE = 2003; const S32 TRANS_GROUP_TAX = 2004; // Taxes incurred as part of group membership const S32 TRANS_CLASSIFIED_RENEW = 2005; +// Codes 2100-2999 reserved for recurring billing services +// New codes can be created through an admin interface so may not +// automatically end up in the list below :-( +// So make sure you check the transaction_description table +const S32 TRANS_RECURRING_GENERIC = 2100; + // Codes 3000-3999 reserved for inventory transactions const S32 TRANS_GIVE_INVENTORY = 3000; @@ -84,6 +90,12 @@ const S32 TRANS_DWELL_BONUS = 5007; const S32 TRANS_PAY_OBJECT = 5008; const S32 TRANS_OBJECT_PAYS = 5009; +// Codes 5100-5999 reserved for recurring billing transfers between users +// New codes can be created through an admin interface so may not +// automatically end up in the list below :-( +// So make sure you check the transaction_description table +const S32 TRANS_RECURRING_GENERIC_USER = 5100; + // Codes 6000-6999 reserved for group transactions //const S32 TRANS_GROUP_JOIN = 6000; //reserved for future use const S32 TRANS_GROUP_LAND_DEED = 6001; diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index cfd6183ec4..fdcc19d657 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -121,7 +121,7 @@ void LLQuaternion::quantize16(F32 lower, F32 upper) mQ[VZ] = z; mQ[VS] = s; - normQuat(); + normalize(); } void LLQuaternion::quantize8(F32 lower, F32 upper) @@ -131,7 +131,7 @@ void LLQuaternion::quantize8(F32 lower, F32 upper) mQ[VZ] = U8_to_F32(F32_to_U8_ROUND(mQ[VZ], lower, upper), lower, upper); mQ[VS] = U8_to_F32(F32_to_U8_ROUND(mQ[VS], lower, upper), lower, upper); - normQuat(); + normalize(); } // LLVector3 Magnitude and Normalization Functions @@ -346,7 +346,7 @@ const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat) // mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ); //#endif // -// normQuat(); +// normalize(); // return (*this); } diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index 5db9c5be2e..0769f29f23 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -469,20 +469,30 @@ inline const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b) return a; } +const F32 ONE_PART_IN_A_MILLION = 0.000001f; + inline F32 LLQuaternion::normalize() { F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); if (mag > FP_MAG_THRESHOLD) { - F32 oomag = 1.f/mag; - mQ[VX] *= oomag; - mQ[VY] *= oomag; - mQ[VZ] *= oomag; - mQ[VS] *= oomag; + // Floating point error can prevent some quaternions from achieving + // exact unity length. When trying to renormalize such quaternions we + // can oscillate between multiple quantized states. To prevent such + // drifts we only renomalize if the length is far enough from unity. + if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) + { + F32 oomag = 1.f/mag; + mQ[VX] *= oomag; + mQ[VY] *= oomag; + mQ[VZ] *= oomag; + mQ[VS] *= oomag; + } } else { + // we were given a very bad quaternion so we set it to identity mQ[VX] = 0.f; mQ[VY] = 0.f; mQ[VZ] = 0.f; @@ -499,11 +509,15 @@ inline F32 LLQuaternion::normQuat() if (mag > FP_MAG_THRESHOLD) { - F32 oomag = 1.f/mag; - mQ[VX] *= oomag; - mQ[VY] *= oomag; - mQ[VZ] *= oomag; - mQ[VS] *= oomag; + if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) + { + // only renormalize if length not close enough to 1.0 already + F32 oomag = 1.f/mag; + mQ[VX] *= oomag; + mQ[VY] *= oomag; + mQ[VZ] *= oomag; + mQ[VS] *= oomag; + } } else { diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 1e8b5517e4..453286b83d 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -3,6 +3,7 @@ project(llmessage) include(00-Common) +include(GoogleMock) include(LLAddBuildTest) include(LLCommon) include(LLMath) @@ -221,6 +222,7 @@ IF (NOT LINUX AND VIEWER) # llhttpclientadapter.cpp lltrustedmessageservice.cpp lltemplatemessagedispatcher.cpp + llregionpresenceverifier.cpp ) # set(TEST_DEBUG on) set(test_libs @@ -229,6 +231,7 @@ IF (NOT LINUX AND VIEWER) ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} ) LL_ADD_INTEGRATION_TEST( @@ -241,3 +244,4 @@ IF (NOT LINUX AND VIEWER) LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}") ENDIF (NOT LINUX AND VIEWER) + diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 47d49076f4..c044b3d80d 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -100,7 +100,6 @@ public: // LEGACY boost::signals2::connection get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data); - // This method needs to be called from time to time to send out // requests. void processPending(); diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index a4af8e989b..5ff41322b7 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -131,7 +131,7 @@ void LLCurl::Responder::errorWithContent( // virtual void LLCurl::Responder::error(U32 status, const std::string& reason) { - llinfos << status << ": " << reason << llendl; + llinfos << mURL << " [" << status << "]: " << reason << llendl; } // virtual @@ -139,6 +139,11 @@ void LLCurl::Responder::result(const LLSD& content) { } +void LLCurl::Responder::setURL(const std::string& url) +{ + mURL = url; +} + // virtual void LLCurl::Responder::completedRaw( U32 status, @@ -148,7 +153,11 @@ void LLCurl::Responder::completedRaw( { LLSD content; LLBufferStream istr(channels, buffer.get()); - LLSDSerialize::fromXML(content, istr); + if (!LLSDSerialize::fromXML(content, istr)) + { + llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; + } + completed(status, reason, content); } diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index fbd3077cbf..0b58e7c4a5 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -120,8 +120,14 @@ public: // of the header can be parsed. In the ::completed call above only the body is contained in the LLSD. virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content); + // Used internally to set the url for debugging later. + void setURL(const std::string& url); + public: /* but not really -- don't touch this */ U32 mReferenceCount; + + private: + std::string mURL; }; typedef boost::intrusive_ptr<Responder> ResponderPtr; diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 8b90a4c5ca..12ecbb36eb 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -265,6 +265,11 @@ static void request( } } + if (responder) + { + responder->setURL(url); + } + req->setCallback(new LLHTTPClientURLAdaptor(responder)); if (method == LLURLRequest::HTTP_POST && gMessageSystem) diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index b6988224ce..9d3c83f828 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -1,5 +1,5 @@ /** - * @file + * @file llhttpclientadapter.cpp * @brief * * $LicenseInfo:firstyear=2009&license=viewergpl$ diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h index 7f76390d0c..a205a2f260 100644 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -1,5 +1,5 @@ /** - * @file + * @file llhttpclientadepter.h * @brief * * $LicenseInfo:firstyear=2008&license=viewergpl$ diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h index 42a8e5cd0a..085a59cf27 100644 --- a/indra/llmessage/llhttpclientinterface.h +++ b/indra/llmessage/llhttpclientinterface.h @@ -1,5 +1,5 @@ /** - * @file + * @file llhttpclientinterface.h * @brief * * $LicenseInfo:firstyear=2008&license=viewergpl$ diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index a00dbd1809..97134bd336 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -521,7 +521,7 @@ protected: * seek orfor string assignment. * @returns Returns true if a line was found. */ - bool readLine( + bool readHeaderLine( const LLChannelDescriptors& channels, buffer_ptr_t buffer, U8* dest, @@ -592,7 +592,7 @@ LLHTTPResponder::~LLHTTPResponder() //lldebugs << "destroying LLHTTPResponder" << llendl; } -bool LLHTTPResponder::readLine( +bool LLHTTPResponder::readHeaderLine( const LLChannelDescriptors& channels, buffer_ptr_t buffer, U8* dest, @@ -670,7 +670,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( #endif PUMP_DEBUG; - if(readLine(channels, buffer, (U8*)buf, len)) + if(readHeaderLine(channels, buffer, (U8*)buf, len)) { bool read_next_line = false; bool parse_all = true; @@ -734,7 +734,13 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( if(read_next_line) { len = HEADER_BUFFER_SIZE; - readLine(channels, buffer, (U8*)buf, len); + if (!readHeaderLine(channels, buffer, (U8*)buf, len)) + { + // Failed to read the header line, probably too long. + // readHeaderLine already marked the channel/buffer as bad. + keep_parsing = false; + break; + } } if(0 == len) { diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index d52ff6c7e8..ce206d8d7d 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -265,7 +265,7 @@ std::string LLMail::buildSMTPTransaction( // static bool LLMail::send( const std::string& header, - const std::string& message, + const std::string& raw_message, const char* from_address, const char* to_address) { @@ -276,8 +276,20 @@ bool LLMail::send( return false; } - // *FIX: this translation doesn't deal with a single period on a - // line by itself. + // remove any "." SMTP commands to prevent injection (DEV-35777) + // we don't need to worry about "\r\n.\r\n" because of the + // "\n" --> "\n\n" conversion going into rfc2822_msg below + std::string message = raw_message; + std::string bad_string = "\n.\n"; + std::string good_string = "\n..\n"; + while (1) + { + int index = message.find(bad_string); + if (index == std::string::npos) break; + message.replace(index, bad_string.size(), good_string); + } + + // convert all "\n" into "\r\n" std::ostringstream rfc2822_msg; for(U32 i = 0; i < message.size(); ++i) { diff --git a/indra/llmessage/llmessagesenderinterface.h b/indra/llmessage/llmessagesenderinterface.h index 119eb1d7f7..af6733fa05 100644 --- a/indra/llmessage/llmessagesenderinterface.h +++ b/indra/llmessage/llmessagesenderinterface.h @@ -1,5 +1,5 @@ /** - * @file + * @file llmessagesenderinterface.h * @brief * * $LicenseInfo:firstyear=2008&license=viewergpl$ diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp index 0527d5cb8d..e02c735ce7 100644 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ b/indra/llmessage/llregionpresenceverifier.cpp @@ -1,5 +1,5 @@ /** - * @file + * @file llregionpresenceverifier.cpp * @brief * * $LicenseInfo:firstyear=2008&license=viewergpl$ @@ -36,11 +36,40 @@ #include "net.h" #include "message.h" +namespace boost +{ + void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p) + { + ++p->mReferenceCount; + } + + void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p) + { + if(p && 0 == --p->mReferenceCount) + { + delete p; + } + } +}; -LLRegionPresenceVerifier::RegionResponder::RegionResponder(ResponsePtr data) : mSharedData(data) +LLRegionPresenceVerifier::Response::~Response() { } +LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string& + uri, + ResponsePtr data, + S32 retry_count) : + mUri(uri), + mSharedData(data), + mRetryCount(retry_count) +{ +} + +//virtual +LLRegionPresenceVerifier::RegionResponder::~RegionResponder() +{ +} void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content) { @@ -49,30 +78,36 @@ void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content) LLHost destination(host, port); LLUUID id = content["region_id"]; - llinfos << "Verifying " << destination.getString() << " is region " << id << llendl; + lldebugs << "Verifying " << destination.getString() << " is region " << id << llendl; std::stringstream uri; uri << "http://" << destination.getString() << "/state/basic/"; - mSharedData->getHttpClient().get(uri.str(), new VerifiedDestinationResponder(mSharedData, content)); + mSharedData->getHttpClient().get( + uri.str(), + new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount)); } -void LLRegionPresenceVerifier::RegionResponder::completed( - U32 status, - const std::string& reason, - const LLSD& content) +void LLRegionPresenceVerifier::RegionResponder::error(U32 status, + const std::string& reason) { - LLHTTPClient::Responder::completed(status, reason, content); - - mSharedData->onCompletedRegionRequest(); + // TODO: babbage: distinguish between region presence service and + // region verification errors? + mSharedData->onRegionVerificationFailed(); } - -LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(ResponsePtr data, const LLSD& content) : mSharedData(data), mContent(content) +LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content, + S32 retry_count): + mUri(uri), + mSharedData(data), + mContent(content), + mRetryCount(retry_count) { } - - +//virtual +LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder() +{ +} void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content) { @@ -87,13 +122,14 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& { mSharedData->onRegionVerified(mContent); } - else if (mSharedData->shouldRetry()) + else if (mRetryCount > 0) { retry(); } else { - llwarns << "Could not correctly look up region from region presence service. Region: " << mSharedData->getRegionUri() << llendl; + llwarns << "Simulator verification failed. Region: " << mUri << llendl; + mSharedData->onRegionVerificationFailed(); } } @@ -101,13 +137,21 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry() { LLSD headers; headers["Cache-Control"] = "no-cache, max-age=0"; - llinfos << "Requesting region information, get uncached for region " << mSharedData->getRegionUri() << llendl; - mSharedData->decrementRetries(); - mSharedData->getHttpClient().get(mSharedData->getRegionUri(), new RegionResponder(mSharedData), headers); + llinfos << "Requesting region information, get uncached for region " + << mUri << llendl; + --mRetryCount; + mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers); } void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason) { - retry(); + if(mRetryCount > 0) + { + retry(); + } + else + { + llwarns << "Failed to contact simulator for verification. Region: " << mUri << llendl; + mSharedData->onRegionVerificationFailed(); + } } - diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h index 54ad6226d6..f57a62a731 100644 --- a/indra/llmessage/llregionpresenceverifier.h +++ b/indra/llmessage/llregionpresenceverifier.h @@ -1,5 +1,5 @@ /** - * @file + * @file llregionpresenceverifier.cpp * @brief * * $LicenseInfo:firstyear=2008&license=viewergpl$ @@ -37,7 +37,7 @@ #include "llhttpclient.h" #include <string> #include "llsd.h" -#include <boost/shared_ptr.hpp> +#include <boost/intrusive_ptr.hpp> class LLHTTPClientInterface; @@ -47,49 +47,58 @@ public: class Response { public: - virtual ~Response() {} + virtual ~Response() = 0; virtual bool checkValidity(const LLSD& content) const = 0; virtual void onRegionVerified(const LLSD& region_details) = 0; - - virtual void decrementRetries() = 0; + virtual void onRegionVerificationFailed() = 0; virtual LLHTTPClientInterface& getHttpClient() = 0; - virtual std::string getRegionUri() const = 0; - virtual bool shouldRetry() const = 0; - virtual void onCompletedRegionRequest() {} + public: /* but not really -- don't touch this */ + U32 mReferenceCount; }; - typedef boost::shared_ptr<Response> ResponsePtr; + typedef boost::intrusive_ptr<Response> ResponsePtr; class RegionResponder : public LLHTTPClient::Responder { public: - RegionResponder(ResponsePtr data); + RegionResponder(const std::string& uri, ResponsePtr data, + S32 retry_count); + virtual ~RegionResponder(); virtual void result(const LLSD& content); - virtual void completed( - U32 status, - const std::string& reason, - const LLSD& content); + virtual void error(U32 status, const std::string& reason); private: ResponsePtr mSharedData; + std::string mUri; + S32 mRetryCount; }; class VerifiedDestinationResponder : public LLHTTPClient::Responder { public: - VerifiedDestinationResponder(ResponsePtr data, const LLSD& content); + VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, + const LLSD& content, S32 retry_count); + virtual ~VerifiedDestinationResponder(); virtual void result(const LLSD& content); virtual void error(U32 status, const std::string& reason); + private: void retry(); ResponsePtr mSharedData; LLSD mContent; + std::string mUri; + S32 mRetryCount; }; }; +namespace boost +{ + void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p); + void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p); +}; #endif //LL_LLREGIONPRESENCEVERIFIER_H diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp index 32cbb15cb3..d6b2f45d04 100644 --- a/indra/llmessage/llstoredmessage.cpp +++ b/indra/llmessage/llstoredmessage.cpp @@ -1,5 +1,5 @@ /** - * @file + * @file llstoredmessage.cpp * @brief * * $LicenseInfo:firstyear=2009&license=viewergpl$ diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h index 5069c2cb2e..359e4c5aea 100644 --- a/indra/llmessage/llstoredmessage.h +++ b/indra/llmessage/llstoredmessage.h @@ -1,5 +1,5 @@ /** - * @file + * @file llstoredmessage.h * @brief * * $LicenseInfo:firstyear=2009&license=viewergpl$ diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp index 70279a3c62..0872efba50 100644 --- a/indra/llmessage/llthrottle.cpp +++ b/indra/llmessage/llthrottle.cpp @@ -265,6 +265,31 @@ BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec) return changed; } +// Return bits available in the channel +S32 LLThrottleGroup::getAvailable(S32 throttle_cat) +{ + S32 retval = 0; + + F32 category_bps = mCurrentBPS[throttle_cat]; + F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME; + + // use a temporary bits_available + // since we don't want to change mBitsAvailable every time + F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]); + F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time); + + if (bits_available >= lookahead_bits) + { + retval = (S32) gThrottleMaximumBPS[throttle_cat]; + } + else + { + retval = (S32) bits_available; + } + + return retval; +} + BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits) { diff --git a/indra/llmessage/llthrottle.h b/indra/llmessage/llthrottle.h index 7d1679beb2..47a7c653b2 100644 --- a/indra/llmessage/llthrottle.h +++ b/indra/llmessage/llthrottle.h @@ -84,6 +84,8 @@ public: BOOL dynamicAdjust(); // Shift bandwidth from idle channels to busy channels, TRUE if adjustment occurred BOOL setNominalBPS(F32* throttle_vec); // TRUE if any value was different, resets adjustment system if was different + S32 getAvailable(S32 throttle_cat); // Return bits available in the channel + void packThrottle(LLDataPacker &dp) const; void unpackThrottle(LLDataPacker &dp); public: diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 5a1cd95ffc..41f3f3f607 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -270,7 +270,6 @@ bool is_asset_fetch_by_id_allowed(LLAssetType::EType type) case LLAssetType::AT_BODYPART: case LLAssetType::AT_ANIMATION: case LLAssetType::AT_GESTURE: - case LLAssetType::AT_FAVORITE: rv = true; break; default: diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 3ab8057abb..81b7761ed5 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -51,6 +51,7 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499; * String constants */ const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri"); +const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); @@ -247,7 +248,29 @@ LLIOPipe::EStatus LLURLRequest::process_impl( PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); //llinfos << "LLURLRequest::process_impl()" << llendl; - if(!buffer) return STATUS_ERROR; + if (!buffer) return STATUS_ERROR; + + // we're still waiting or prcessing, check how many + // bytes we have accumulated. + const S32 MIN_ACCUMULATION = 100000; + if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) + { + // This is a pretty sloppy calculation, but this + // tries to make the gross assumption that if data + // is coming in at 56kb/s, then this transfer will + // probably succeed. So, if we're accumlated + // 100,000 bytes (MIN_ACCUMULATION) then let's + // give this client another 2s to complete. + const F32 TIMEOUT_ADJUSTMENT = 2.0f; + mDetail->mByteAccumulator = 0; + pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT); + lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl; + if (mState == STATE_INITIALIZED) + { + llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl; + } + } + switch(mState) { case STATE_INITIALIZED: @@ -286,27 +309,14 @@ LLIOPipe::EStatus LLURLRequest::process_impl( bool newmsg = mDetail->mCurlRequest->getResult(&result); if(!newmsg) { - // we're still waiting or prcessing, check how many - // bytes we have accumulated. - const S32 MIN_ACCUMULATION = 100000; - if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) - { - // This is a pretty sloppy calculation, but this - // tries to make the gross assumption that if data - // is coming in at 56kb/s, then this transfer will - // probably succeed. So, if we're accumlated - // 100,000 bytes (MIN_ACCUMULATION) then let's - // give this client another 2s to complete. - const F32 TIMEOUT_ADJUSTMENT = 2.0f; - mDetail->mByteAccumulator = 0; - pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT); - } - // keep processing break; } mState = STATE_HAVE_RESPONSE; + context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; + context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; + lldebugs << this << "Setting context to " << context << llendl; switch(result) { case CURLE_OK: @@ -353,10 +363,16 @@ LLIOPipe::EStatus LLURLRequest::process_impl( // we already stuffed everything into channel in in the curl // callback, so we are done. eos = true; + context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; + context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; + lldebugs << this << "Setting context to " << context << llendl; return STATUS_DONE; default: PUMP_DEBUG; + context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; + context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; + lldebugs << this << "Setting context to " << context << llendl; return STATUS_ERROR; } } @@ -369,6 +385,8 @@ void LLURLRequest::initialize() mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this); mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this); + mRequestTransferedBytes = 0; + mResponseTransferedBytes = 0; } bool LLURLRequest::configure() @@ -471,6 +489,7 @@ size_t LLURLRequest::downCallback( req->mDetail->mChannels.out(), (U8*)data, bytes); + req->mResponseTransferedBytes += bytes; req->mDetail->mByteAccumulator += bytes; return bytes; } @@ -494,6 +513,7 @@ size_t LLURLRequest::upCallback( req->mDetail->mLastRead, (U8*)data, bytes); + req->mRequestTransferedBytes += bytes; return bytes; } diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 86ef71f085..cb3c466440 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -45,6 +45,12 @@ #include "llchainio.h" #include "llerror.h" + +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_DEST_URI_SD_LABEL; +extern const std::string CONTEXT_RESPONSE; +extern const std::string CONTEXT_TRANSFERED_BYTES; + class LLURLRequestDetail; class LLURLRequestComplete; @@ -208,6 +214,8 @@ protected: ERequestAction mAction; LLURLRequestDetail* mDetail; LLIOPipe::ptr_t mCompletionCallback; + S32 mRequestTransferedBytes; + S32 mResponseTransferedBytes; private: /** diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 08c9192c9f..209bdb2249 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -760,30 +760,36 @@ static bool remove_prefix(std::string& filename, const std::string& prefix) static bool verify_cache_filename(const std::string& filename) { //NOTE: This routine is only used to check file names that our own - // code places in the cache directory. As such, it can be limited - // to this very restrictive file name pattern. It does not need to - // handle other characters. - + // code places in the cache directory. As such, it can be limited + // to this very restrictive file name pattern. It does not need to + // handle other characters. The only known uses of this are (with examples): + // sim to sim object pass: fc0b72d8-9456-63d9-a802-a557ef847313.tmp + // sim to viewer mute list: mute_b78eacd0-1244-448e-93ca-28ede242f647.tmp + // sim to viewer task inventory: inventory_d8ab59d2-baf0-0e79-c4c2-a3f99b9fcf45.tmp + + //IMPORTANT: Do not broaden the filenames accepted by this routine + // without careful analysis. Anything allowed by this function can + // be downloaded by the viewer. + size_t len = filename.size(); - //const boost::regex expr("[a-zA-Z0-9][-_.a-zA-Z0-9]<0,49>"); - if (len < 1 || len > 50) - { + //const boost::regex expr("[0-9a-zA-Z_-]<1,46>\.tmp"); + if (len < 5 || len > 50) + { return false; } - for(unsigned i=0; i<len; ++i) - { + for(size_t i=0; i<(len-4); ++i) + { char c = filename[i]; - bool ok = isalnum(c); - if (!ok && i > 0) - { - ok = '_'==c || '-'==c || '.'==c; - } + bool ok = isalnum(c) || '_'==c || '-'==c; if (!ok) { return false; } } - return true; + return filename[len-4] == '.' + && filename[len-3] == 't' + && filename[len-2] == 'm' + && filename[len-1] == 'p'; } void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/) diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index 5dc5932fde..e6a5ad9946 100644 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -22,6 +22,7 @@ #include "linden_common.h" LLCurl::Responder::Responder() + : mReferenceCount(0) { } diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h new file mode 100644 index 0000000000..2f55e97fcc --- /dev/null +++ b/indra/llmessage/tests/llmockhttpclient.h @@ -0,0 +1,61 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of + * this source code is governed by the Linden Lab Source Code Disclosure + * Agreement ("Agreement") previously entered between you and Linden + * Lab. By accessing, using, copying, modifying or distributing this + * software, you acknowledge that you have been informed of your + * obligations under the Agreement 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$ + */ + +/* Macro Definitions */ +#ifndef LL_LLMOCKHTTPCLIENT_H +#define LL_LLMOCKHTTPCLIENT_H + +#include "linden_common.h" +#include "llhttpclientinterface.h" + +#include <gmock/gmock.h> + +class LLMockHTTPClient : public LLHTTPClientInterface +{ +public: + MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder)); + MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)); + MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)); +}; + +// A helper to match responder types +template<typename T> +struct ResponderType +{ + bool operator()(LLCurl::ResponderPtr ptr) const + { + T* p = dynamic_cast<T*>(ptr.get()); + return p != NULL; + } +}; + +inline bool operator==(const LLSD& l, const LLSD& r) +{ + std::ostringstream ls, rs; + ls << l; + rs << r; + return ls.str() == rs.str(); + +} + + +#endif //LL_LLMOCKHTTPCLIENT_H + diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp new file mode 100644 index 0000000000..b7602ef15c --- /dev/null +++ b/indra/llmessage/tests/llregionpresenceverifier_test.cpp @@ -0,0 +1,111 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2001-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 "../test/lltut.h" +#include "llregionpresenceverifier.h" +#include "llcurl_stub.cpp" +#include "llhost.cpp" +#include "net.cpp" +#include "lltesthttpclientadapter.cpp" + +class LLTestResponse : public LLRegionPresenceVerifier::Response +{ +public: + + virtual bool checkValidity(const LLSD& content) const + { + return true; + } + + virtual void onRegionVerified(const LLSD& region_details) + { + } + + virtual void onRegionVerificationFailed() + { + } + + virtual LLHTTPClientInterface& getHttpClient() + { + return mHttpInterface; + } + + LLTestHTTPClientAdapter mHttpInterface; +}; + +namespace tut +{ + struct LLRegionPresenceVerifierData + { + LLRegionPresenceVerifierData() : + mResponse(new LLTestResponse()), + mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse), + LLSD(), 3) + { + } + + LLTestResponse* mResponse; + LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder; + }; + + typedef test_group<LLRegionPresenceVerifierData> factory; + typedef factory::object object; +} + +namespace +{ + tut::factory tf("LLRegionPresenceVerifier test"); +} + +namespace tut +{ + // Test that VerifiedDestinationResponder does retry + // on error when shouldRetry returns true. + template<> template<> + void object::test<1>() + { + mResponder.error(500, "Internal server error"); + ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1); + } + + // Test that VerifiedDestinationResponder only retries + // on error until shouldRetry returns false. + template<> template<> + void object::test<2>() + { + mResponder.error(500, "Internal server error"); + mResponder.error(500, "Internal server error"); + mResponder.error(500, "Internal server error"); + mResponder.error(500, "Internal server error"); + ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3); + } +} + diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 7299ede22d..e019cdcf21 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -884,6 +884,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) } /* virtual */ +void LLPluginClassMedia::pluginLaunchFailed() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); +} + +/* virtual */ void LLPluginClassMedia::pluginDied() { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 331ca5f6dc..97f2a11ef2 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -135,6 +135,7 @@ public: // Inherited from LLPluginProcessParentOwner /* virtual */ void receivePluginMessage(const LLPluginMessage &message); + /* virtual */ void pluginLaunchFailed(); /* virtual */ void pluginDied(); diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index df6de0925e..cfee847080 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -56,7 +56,8 @@ public: MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are MEDIA_EVENT_CLICK_LINK_NOFOLLOW, - MEDIA_EVENT_PLUGIN_FAILED // The plugin failed to launch or died unexpectedly + MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch + MEDIA_EVENT_PLUGIN_FAILED // The plugin died unexpectedly } EMediaEvent; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 41784a713c..f3b4c6bdc6 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -83,6 +83,14 @@ void LLPluginProcessParent::killSockets(void) mSocket.reset(); } +void LLPluginProcessParent::errorState(void) +{ + if(mState < STATE_RUNNING) + setState(STATE_LAUNCH_FAILURE); + else + setState(STATE_ERROR); +} + void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename) { mProcess.setExecutable(launcher_filename); @@ -132,7 +140,7 @@ bool LLPluginProcessParent::accept() ll_apr_warn_status(status); // Some other error. - setState(STATE_ERROR); + errorState(); } return result; @@ -150,15 +158,15 @@ void LLPluginProcessParent::idle(void) if(!mMessagePipe->pump()) { // LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL; - setState(STATE_ERROR); + errorState(); } } - if((mSocketError != APR_SUCCESS) && (mState < STATE_ERROR)) + if((mSocketError != APR_SUCCESS) && (mState <= STATE_RUNNING)) { // The socket is in an error state -- the plugin is gone. LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; - setState(STATE_ERROR); + errorState(); } // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). @@ -191,7 +199,7 @@ void LLPluginProcessParent::idle(void) if(ll_apr_warn_status(status)) { killSockets(); - setState(STATE_ERROR); + errorState(); break; } @@ -202,7 +210,7 @@ void LLPluginProcessParent::idle(void) if(ll_apr_warn_status(status)) { killSockets(); - setState(STATE_ERROR); + errorState(); break; } @@ -212,7 +220,7 @@ void LLPluginProcessParent::idle(void) if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) { killSockets(); - setState(STATE_ERROR); + errorState(); break; } mBoundPort = bound_addr->port; @@ -222,7 +230,7 @@ void LLPluginProcessParent::idle(void) LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; killSockets(); - setState(STATE_ERROR); + errorState(); break; } } @@ -234,7 +242,7 @@ void LLPluginProcessParent::idle(void) if(ll_apr_warn_status(status)) { killSockets(); - setState(STATE_ERROR); + errorState(); break; } @@ -242,7 +250,7 @@ void LLPluginProcessParent::idle(void) if(ll_apr_warn_status(status)) { killSockets(); - setState(STATE_ERROR); + errorState(); break; } @@ -255,7 +263,7 @@ void LLPluginProcessParent::idle(void) if(ll_apr_warn_status(status)) { killSockets(); - setState(STATE_ERROR); + errorState(); break; } @@ -274,7 +282,7 @@ void LLPluginProcessParent::idle(void) mProcess.addArgument(stream.str()); if(mProcess.launch() != 0) { - setState(STATE_ERROR); + errorState(); } else { @@ -290,7 +298,7 @@ void LLPluginProcessParent::idle(void) // waiting for the plugin to connect if(pluginLockedUpOrQuit()) { - setState(STATE_ERROR); + errorState(); } else { @@ -309,7 +317,7 @@ void LLPluginProcessParent::idle(void) if(pluginLockedUpOrQuit()) { - setState(STATE_ERROR); + errorState(); } break; @@ -330,14 +338,14 @@ void LLPluginProcessParent::idle(void) // The load_plugin_response message will kick us from here into STATE_RUNNING if(pluginLockedUpOrQuit()) { - setState(STATE_ERROR); + errorState(); } break; case STATE_RUNNING: if(pluginLockedUpOrQuit()) { - setState(STATE_ERROR); + errorState(); } break; @@ -349,8 +357,16 @@ void LLPluginProcessParent::idle(void) else if(pluginLockedUp()) { LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl; - setState(STATE_ERROR); + errorState(); + } + break; + + case STATE_LAUNCH_FAILURE: + if(mOwner != NULL) + { + mOwner->pluginLaunchFailed(); } + setState(STATE_CLEANUP); break; case STATE_ERROR: @@ -467,7 +483,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) else { LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL; - setState(STATE_ERROR); + errorState(); } } @@ -477,6 +493,9 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { // Plugin has been loaded. + mPluginVersionString = message.getValue("plugin_version"); + LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL; + // Check which message classes/versions the plugin supports. // TODO: check against current versions // TODO: kill plugin on major mismatches? @@ -487,8 +506,6 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL; } - mPluginVersionString = message.getValue("plugin_version"); - // Send initial sleep time setSleepTime(mSleepTime, true); @@ -497,7 +514,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) else { LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL; - setState(STATE_ERROR); + errorState(); } } else if(message_name == "heartbeat") diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 0d0b047c88..754ebeb946 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -45,6 +45,7 @@ public: virtual ~LLPluginProcessParentOwner(); virtual void receivePluginMessage(const LLPluginMessage &message) = 0; // This will only be called when the plugin has died unexpectedly + virtual void pluginLaunchFailed() {}; virtual void pluginDied() {}; }; @@ -68,6 +69,9 @@ public: bool isDone(void); void killSockets(void); + + // Go to the proper error state + void errorState(void); void setSleepTime(F64 sleep_time, bool force_send = false); F64 getSleepTime(void) const { return mSleepTime; }; @@ -110,6 +114,7 @@ private: STATE_HELLO, // first message from the plugin process has been received STATE_LOADING, // process has been asked to load the plugin STATE_RUNNING, // + STATE_LAUNCH_FAILURE, // Failure before plugin loaded STATE_ERROR, // generic bailout state STATE_CLEANUP, // clean everything up STATE_EXITING, // Tried to kill process, waiting for it to exit diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index b102254b62..d307d4bbfb 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -746,16 +746,201 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai U32 old_face_mask = mVolumep->mFaceMask; + S32 face_bit = 0; + S32 cur_mask = 0; + + // Grab copies of the old faces from the original shape, ordered by type. + // We will use these to figure out what old texture info gets mapped to new + // faces in the new shape. + std::vector<LLProfile::Face> old_faces; + for (S32 face = 0; face < mVolumep->getNumFaces(); face++) + { + old_faces.push_back(mVolumep->getProfile().mFaces[face]); + } + + // Copy the old texture info off to the side, but not in the order in which + // they live in the mTextureList, rather in order of ther "face id" which + // is the corresponding value of LLVolueParams::LLProfile::mFaces::mIndex. + // + // Hence, some elements of old_tes::mEntryList will be invalid. It is + // initialized to a size of 9 (max number of possible faces on a volume?) + // and only the ones with valid types are filled in. + LLPrimTextureList old_tes; + old_tes.setSize(9); + for (face_bit = 0; face_bit < 9; face_bit++) + { + cur_mask = 0x1 << face_bit; + if (old_face_mask & cur_mask) + { + S32 te_index = face_index_from_id(cur_mask, old_faces); + old_tes.copyTexture(face_bit, *(getTE(te_index))); + //llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl; + } + } + + // build the new object sVolumeManager->unrefVolume(mVolumep); mVolumep = volumep; U32 new_face_mask = mVolumep->mFaceMask; - if (old_face_mask != new_face_mask) + S32 i; + + if (old_face_mask == new_face_mask) { + // nothing to do + return TRUE; + } + + if (mVolumep->getNumFaces() == 0 && new_face_mask != 0) + { + llwarns << "Object with 0 faces found...INCORRECT!" << llendl; setNumTEs(mVolumep->getNumFaces()); + return TRUE; + } + + // initialize face_mapping + S32 face_mapping[9]; + for (face_bit = 0; face_bit < 9; face_bit++) + { + face_mapping[face_bit] = face_bit; + } + + // The new shape may have more faces than the original, but we can't just + // add them to the end -- the ordering matters and it may be that we must + // insert the new faces in the middle of the list. When we add a face it + // will pick up the texture/color info of one of the old faces an so we + // now figure out which old face info gets mapped to each new face, and + // store in the face_mapping lookup table. + for (face_bit = 0; face_bit < 9; face_bit++) + { + cur_mask = 0x1 << face_bit; + if (!(new_face_mask & cur_mask)) + { + // Face doesn't exist in new map. + face_mapping[face_bit] = -1; + continue; + } + else if (old_face_mask & cur_mask) + { + // Face exists in new and old map. + face_mapping[face_bit] = face_bit; + continue; + } + + // OK, how we've got a mismatch, where we have to fill a new face with one from + // the old face. + if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE)) + { + // It's a top/bottom/hollow interior face. + if (old_face_mask & LL_FACE_PATH_END) + { + face_mapping[face_bit] = 1; + continue; + } + else + { + S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; + for (i = 0; i < 4; i++) + { + if (old_face_mask & cur_outer_mask) + { + face_mapping[face_bit] = 5 + i; + break; + } + cur_outer_mask <<= 1; + } + if (i == 4) + { + llwarns << "No path end or outer face in volume!" << llendl; + } + continue; + } + } + + if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) + { + // A cut slice. Use the hollow interior if we have it. + if (old_face_mask & LL_FACE_INNER_SIDE) + { + face_mapping[face_bit] = 2; + continue; + } + + // No interior, use the bottom face. + // Could figure out which of the outer faces was nearest, but that would be harder. + if (old_face_mask & LL_FACE_PATH_END) + { + face_mapping[face_bit] = 1; + continue; + } + else + { + S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; + for (i = 0; i < 4; i++) + { + if (old_face_mask & cur_outer_mask) + { + face_mapping[face_bit] = 5 + i; + break; + } + cur_outer_mask <<= 1; + } + if (i == 4) + { + llwarns << "No path end or outer face in volume!" << llendl; + } + continue; + } + } + + // OK, the face that's missing is an outer face... + // Pull from the nearest adjacent outer face (there's always guaranteed to be one... + S32 cur_outer = face_bit - 5; + S32 min_dist = 5; + S32 min_outer_bit = -1; + S32 i; + for (i = 0; i < 4; i++) + { + if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i)) + { + S32 dist = abs(i - cur_outer); + if (dist < min_dist) + { + min_dist = dist; + min_outer_bit = i + 5; + } + } + } + if (-1 == min_outer_bit) + { + llinfos << (LLVolume *)mVolumep << llendl; + llwarns << "Bad! No outer faces, impossible!" << llendl; + } + face_mapping[face_bit] = min_outer_bit; } + + setNumTEs(mVolumep->getNumFaces()); + for (face_bit = 0; face_bit < 9; face_bit++) + { + // For each possible face type on the new shape we check to see if that + // face exists and if it does we create a texture entry that is a copy + // of one of the originals. Since the originals might not have a + // matching face, we use the face_mapping lookup table to figure out + // which face information to copy. + cur_mask = 0x1 << face_bit; + if (new_face_mask & cur_mask) + { + if (-1 == face_mapping[face_bit]) + { + llwarns << "No mapping from old face to new face!" << llendl; + } + + S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces); + setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit]))); + } + } return TRUE; } @@ -1715,10 +1900,10 @@ LLSD LLLightImageParams::asLLSD() const bool LLLightImageParams::fromLLSD(LLSD& sd) { - if (sd.has("texture") && sd.has("params") && sd["params"].size() == 3) + if (sd.has("texture")) { setLightTexture( sd["texture"] ); - setParams( LLVector3(sd["params"][0].asReal(), sd["params"][1].asReal(), sd["params"][2].asReal()) ); + setParams( LLVector3( sd["params"] ) ); return true; } diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index d03150fc78..1c7de95975 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -135,13 +135,12 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) { if (S32(index) >= mEntryList.size()) { - // TODO -- assert here S32 current_size = mEntryList.size(); - llerrs << "index = " << S32(index) << " current_size = " << current_size << llendl; + llwarns << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << llendl; return TEM_CHANGE_NONE; } - // we're changing an existing entry + // we're changing an existing entry llassert(mEntryList[index]); delete (mEntryList[index]); if (&te) @@ -387,8 +386,18 @@ void LLPrimTextureList::setSize(S32 new_size) mEntryList.resize(new_size); for (S32 index = current_size; index < new_size; ++index) { - LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); - mEntryList[index] = new_entry; + if (current_size > 0 + && mEntryList[current_size - 1]) + { + // copy the last valid entry for the new one + mEntryList[index] = mEntryList[current_size - 1]->newCopy(); + } + else + { + // no valid enries to copy, so we new one up + LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); + mEntryList[index] = new_entry; + } } } else if (new_size < current_size) diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index b534939dfc..8f7cd68834 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -646,3 +646,9 @@ LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &versi } return id; } + +//static +bool LLTextureEntry::isMediaVersionString(const std::string &version_string) +{ + return std::string::npos != version_string.find(MEDIA_VERSION_STRING_PREFIX); +} diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index 8d2834f78c..d6366b9bb2 100644 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -171,7 +171,9 @@ public: static U32 getVersionFromMediaVersionString(const std::string &version_string); // Given a media version string, return the UUID of the agent static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string); - + // Return whether or not the given string is actually a media version + static bool isMediaVersionString(const std::string &version_string); + // Media flags enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 }; diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 4525f0a45b..c512ef25be 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -91,6 +91,16 @@ void LLDockableFloater::setVisible(BOOL visible) LLFloater::setVisible(visible); } +void LLDockableFloater::onDockHidden() +{ + setCanDock(FALSE); +} + +void LLDockableFloater::onDockShown() +{ + setCanDock(TRUE); +} + void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) { if (mDockControl.get() != NULL && mDockControl.get()->isDockVisible()) diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index ed90567ad3..7d91d007ee 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -68,6 +68,9 @@ public: */ /*virtual*/ void setVisible(BOOL visible); + virtual void onDockHidden(); + virtual void onDockShown(); + private: /** * Provides unique of dockable floater. diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index 146c7a969a..cdcd823b1c 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "lldockcontrol.h" +#include "lldockablefloater.h" LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) : @@ -91,8 +92,8 @@ void LLDockControl::repositionDockable() // recalculate dockable position if dock position changed, dock visibility changed, // root view rect changed or recalculation is forced - if (mEnabled && (mPrevDockRect != dockRect || prev_visibility != mDockWidget->getVisible() - || mRootRect != rootRect || mRecalculateDocablePosition)) + if (mPrevDockRect != dockRect || prev_visibility != mDockWidget->getVisible() + || mRootRect != rootRect || mRecalculateDocablePosition) { // undock dockable and off() if dock not visible if (!isDockVisible()) @@ -100,10 +101,25 @@ void LLDockControl::repositionDockable() mDockableFloater->setDocked(false); // force off() since dockable may not have dockControll at this time off(); + LLDockableFloater* dockable_floater = + dynamic_cast<LLDockableFloater*> (mDockableFloater); + if(dockable_floater != NULL) + { + dockable_floater->onDockHidden(); + } } else { - moveDockable(); + if(mEnabled) + { + moveDockable(); + } + LLDockableFloater* dockable_floater = + dynamic_cast<LLDockableFloater*> (mDockableFloater); + if(dockable_floater != NULL) + { + dockable_floater->onDockShown(); + } } mPrevDockRect = dockRect; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 564e4d748f..b7a15a2b33 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -664,7 +664,8 @@ void LLFloater::closeFloater(bool app_quitting) dirtyRect(); - // Close callback + // Close callbacks + onClose(app_quitting); mCloseSignal(this, LLSD(app_quitting)); // Hide or Destroy diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 1dc5177f81..17ffc94014 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -208,8 +208,8 @@ public: virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual void draw(); - // *TODO: Eliminate this in favor of mOpenSignal virtual void onOpen(const LLSD& key) {} + virtual void onClose(bool app_quitting) {} // This cannot be "const" until all derived floater canClose() // methods are const as well. JC @@ -293,11 +293,18 @@ private: void addResizeCtrls(); void addDragHandle(); +public: + // Called when floater is opened, passes mKey + // Public so external views or floaters can watch for this floater opening + commit_signal_t mOpenSignal; + + // Called when floater is closed, passes app_qitting as LLSD() + // Public so external views or floaters can watch for this floater closing + commit_signal_t mCloseSignal; + protected: std::string mRectControl; std::string mVisibilityControl; - commit_signal_t mOpenSignal; // Called when floater is opened, passes mKey - commit_signal_t mCloseSignal; // Called when floater is closed, passes app_qitting as LLSD() LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg LLDragHandle* mDragHandle; diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 2bb6749c83..8dbcd6e229 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -83,6 +83,12 @@ void LLMenuButton::toggleMenu() } +void LLMenuButton::hideMenu() +{ + mMenu->setVisible(FALSE); +} + + BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask ) { if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 94b0e4355d..02eb9d3806 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -54,6 +54,7 @@ public: /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); + void hideMenu(); protected: friend class LLUICtrlFactory; diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 1695aee2b8..69ff3dddc3 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -522,7 +522,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu // be built/added. JC if (parent) { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); parent->addChild(this, tab_group); } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 62f03f47e6..3dacf979c7 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -807,6 +807,9 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) ++cur_seg_iter; } } + + // layout potentially changed + needsReflow(); } BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 8f5c029816..c55273cacf 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -38,6 +38,7 @@ // Library includes #include "lltextbox.h" #include "lliconctrl.h" +#include "llmenugl.h" // hideMenus() #include "llui.h" // positionViewNearMouse() #include "llwindow.h" @@ -94,7 +95,16 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolTipView::handleMouseDown(S32 x, S32 y, MASK mask) { LLToolTipMgr::instance().blockToolTips(); - return LLView::handleMouseDown(x, y, mask); + + if (LLView::handleMouseDown(x, y, mask)) + { + // If we are handling the mouse event menu holder + // won't get a chance to close menus so do this here + LLMenuGL::sMenuContainer->hideMenus(); + return TRUE; + } + + return FALSE; } BOOL LLToolTipView::handleMiddleMouseDown(S32 x, S32 y, MASK mask) @@ -189,7 +199,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p) addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_params)); // move text over to fit image in - mTextBox->translate(TOOLTIP_ICON_SIZE,0); + mTextBox->translate(TOOLTIP_ICON_SIZE + mPadding, 0); } if (p.click_callback.isProvided()) diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index e47010c316..3c77c655b8 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -321,7 +321,7 @@ fail: static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); private: - //static void setCtrlValue(LLView* view, LLXMLNodePtr node); + // this exists to get around dependency on llview static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); // Avoid directly using LLUI and LLDir in the template code diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp index 93ac120302..315baa001d 100755 --- a/indra/llvfs/llpidlock.cpp +++ b/indra/llvfs/llpidlock.cpp @@ -62,7 +62,7 @@ class LLPidLockFile mSaving(FALSE), mWaiting(FALSE), mClean(TRUE), mPID(getpid()) { - mLockName = gDirUtilp->getTempDir() + "/savelock"; + mLockName = gDirUtilp->getTempDir() + gDirUtilp->getDirDelimiter() + "savelock"; } bool requestLock(LLNameTable<void *> *name_table, bool autosave, bool force_immediate=FALSE, F32 timeout=300.0); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index d2760e3d59..7137c93476 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -2763,10 +2763,6 @@ const char* cursorIDToName(int id) case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; - case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; - case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLPAY: return "UI_CURSOR_TOOLPAY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; @@ -2862,10 +2858,6 @@ void LLWindowMacOSX::setCursor(ECursorType cursor) case UI_CURSOR_TOOLPAN: case UI_CURSOR_TOOLZOOMIN: case UI_CURSOR_TOOLPICKOBJECT3: - case UI_CURSOR_TOOLSIT: - case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLPAY: - case UI_CURSOR_TOOLOPEN: case UI_CURSOR_TOOLPLAY: case UI_CURSOR_TOOLPAUSE: case UI_CURSOR_TOOLMEDIAOPEN: @@ -2907,10 +2899,6 @@ void LLWindowMacOSX::initCursors() initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSIT, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLBUY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPAY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLOPEN, 1, 1); initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index ecda880c1f..00a8d429ba 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -1981,10 +1981,6 @@ void LLWindowSDL::initCursors() mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5); mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5); mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLPAY] = makeSDLCursorFromBMP("toolpay.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",0,0); mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0); mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0); mSDLCursors[UI_CURSOR_TOOLMEDIAOPEN] = makeSDLCursorFromBMP("toolmediaopen.BMP",0,0); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 0faa3e93ff..c608c21d05 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1527,10 +1527,6 @@ void LLWindowWin32::initCursors() mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); // Color cursors - mCursor[UI_CURSOR_TOOLSIT] = loadColorCursor(TEXT("TOOLSIT")); - mCursor[UI_CURSOR_TOOLBUY] = loadColorCursor(TEXT("TOOLBUY")); - mCursor[UI_CURSOR_TOOLPAY] = loadColorCursor(TEXT("TOOLPAY")); - mCursor[UI_CURSOR_TOOLOPEN] = loadColorCursor(TEXT("TOOLOPEN")); mCursor[UI_CURSOR_TOOLPLAY] = loadColorCursor(TEXT("TOOLPLAY")); mCursor[UI_CURSOR_TOOLPAUSE] = loadColorCursor(TEXT("TOOLPAUSE")); mCursor[UI_CURSOR_TOOLMEDIAOPEN] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); diff --git a/indra/lscript/lscript_byteformat.h b/indra/lscript/lscript_byteformat.h index ba2c46bef2..a54ebd5831 100644 --- a/indra/lscript/lscript_byteformat.h +++ b/indra/lscript/lscript_byteformat.h @@ -556,7 +556,7 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] = // http_request string constants extern const char* URL_REQUEST_GRANTED; extern const char* URL_REQUEST_DENIED; -extern const U64 LSL_HTTP_REQUEST_TIMEOUT; +extern const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC; #endif diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp index 98146d6f2b..3b8bbbe805 100644 --- a/indra/lscript/lscript_compile/lscript_tree.cpp +++ b/indra/lscript/lscript_compile/lscript_tree.cpp @@ -631,9 +631,7 @@ static void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetTy switch(targetType) { case LST_INTEGER: - //fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)\n"); - fprintf(fp, "conv.i4\n"); // TODO replace this line with the above - // we the entire grid is > 1.25.1 + fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)\n"); break; case LST_STRING: fprintf(fp, "call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ToString(float32)\n"); @@ -8375,10 +8373,18 @@ void LLScriptStateChange::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp chunk->addInteger(mIdentifier->mScopeEntry->mCount); } break; + case LSCP_TYPE: + mReturnType = basetype; + break; case LSCP_EMIT_CIL_ASSEMBLY: fprintf(fp, "ldarg.0\n"); fprintf(fp, "ldstr \"%s\"\n", mIdentifier->mName); fprintf(fp, "call instance void class [LslUserScript]LindenLab.SecondLife.LslUserScript::ChangeState(string)\n"); + // We are doing a state change. In the LSL interpreter, this is basically a longjmp. We emulate it + // here using a call to the ChangeState followed by a short cut return of the current method. To + // maintain type safety we need to push an arbitrary variable of the current method's return type + // onto the stack before returning. This will be ignored and discarded. + print_cil_init_variable(fp, mReturnType); fprintf(fp, "ret\n"); break; default: diff --git a/indra/lscript/lscript_compile/lscript_tree.h b/indra/lscript/lscript_compile/lscript_tree.h index 12c16908af..a667e1eb5b 100644 --- a/indra/lscript/lscript_compile/lscript_tree.h +++ b/indra/lscript/lscript_compile/lscript_tree.h @@ -1888,6 +1888,7 @@ public: S32 getSize(); LLScriptIdentifier *mIdentifier; + LSCRIPTType mReturnType; }; class LLScriptJump : public LLScriptStatement diff --git a/indra/lscript/lscript_execute.h b/indra/lscript/lscript_execute.h index 245fc320d1..96855abea0 100644 --- a/indra/lscript/lscript_execute.h +++ b/indra/lscript/lscript_execute.h @@ -371,8 +371,7 @@ class LLScriptExecute { public: LLScriptExecute(); - virtual ~LLScriptExecute() {;} - + virtual ~LLScriptExecute() = 0; virtual S32 getVersion() const = 0; virtual void deleteAllEvents() = 0; virtual void addEvent(LLScriptDataCollection* event) = 0; diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp index 2fd81210c0..e849fa9a6e 100644 --- a/indra/lscript/lscript_execute/lscript_execute.cpp +++ b/indra/lscript/lscript_execute/lscript_execute.cpp @@ -41,6 +41,8 @@ #include "lscript_library.h" #include "lscript_heapruntime.h" #include "lscript_alloc.h" +#include "llstat.h" + // Static const S32 DEFAULT_SCRIPT_TIMER_CHECK_SKIP = 4; @@ -72,7 +74,7 @@ const char* URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED"; const char* URL_REQUEST_DENIED = "URL_REQUEST_DENIED"; // HTTP Requests to LSL scripts will time out after 25 seconds. -const U64 LSL_HTTP_REQUEST_TIMEOUT = 25 * USEC_PER_SEC; +const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC = 25 * USEC_PER_SEC; LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp) { @@ -110,6 +112,7 @@ LLScriptExecuteLSL2::LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size) init(); } +LLScriptExecute::~LLScriptExecute() {} LLScriptExecuteLSL2::~LLScriptExecuteLSL2() { delete[] mBuffer; @@ -4234,19 +4237,16 @@ S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer) return 4; } -BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) + +// Shared code for run_calllib() and run_calllib_two_byte() +BOOL run_calllib_common(U8 *buffer, S32 &offset, const LLUUID &id, U16 arg) { - if (b_print) - printf("[0x%X]\tCALLLIB ", offset); - offset++; - U8 arg = safe_instruction_bytestream2byte(buffer, offset); - if (arg >= (U8)gScriptLibrary.mFunctions.size()) + if (arg >= gScriptLibrary.mFunctions.size()) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return FALSE; } - if (b_print) - printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg].mName); + LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg]; // pull out the arguments and the return values LLScriptLibData *arguments = NULL; @@ -4254,14 +4254,14 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) S32 i, number; - if (gScriptLibrary.mFunctions[arg].mReturnType) + if (function.mReturnType) { returnvalue = new LLScriptLibData; } - if (gScriptLibrary.mFunctions[arg].mArgs) + if (function.mArgs) { - number = (S32)strlen(gScriptLibrary.mFunctions[arg].mArgs); /*Flawfinder: ignore*/ + number = (S32)strlen(function.mArgs); //Flawfinder: ignore arguments = new LLScriptLibData[number]; } else @@ -4271,23 +4271,18 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) for (i = number - 1; i >= 0; i--) { - lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg].mArgs[i]); + lscript_pop_variable(&arguments[i], buffer, function.mArgs[i]); } - if (b_print) - { - printf("See LSLTipText_%s in strings.xml for usage\n", gScriptLibrary.mFunctions[arg].mName); - } + // Actually execute the function call + function.mExecFunc(returnvalue, arguments, id); - { - gScriptLibrary.mFunctions[arg].mExecFunc(returnvalue, arguments, id); - } - add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg].mEnergyUse); - add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg].mSleepTime); + add_register_fp(buffer, LREG_ESR, -(function.mEnergyUse)); + add_register_fp(buffer, LREG_SLR, function.mSleepTime); if (returnvalue) { - returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg].mReturnType); + returnvalue->mType = char2type(*function.mReturnType); lscript_push_return_variable(returnvalue, buffer); } @@ -4304,71 +4299,32 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) } -BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) +BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) { - if (b_print) - printf("[0x%X]\tCALLLIB ", offset); offset++; - U16 arg = safe_instruction_bytestream2u16(buffer, offset); - if (arg >= (U16)gScriptLibrary.mFunctions.size()) + U16 arg = (U16) safe_instruction_bytestream2byte(buffer, offset); + if (b_print && + arg < gScriptLibrary.mFunctions.size()) { - set_fault(buffer, LSRF_BOUND_CHECK_ERROR); - return FALSE; - } - if (b_print) - printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg].mName); - - // pull out the arguments and the return values - LLScriptLibData *arguments = NULL; - LLScriptLibData *returnvalue = NULL; - - S32 i, number; - - if (gScriptLibrary.mFunctions[arg].mReturnType) - { - returnvalue = new LLScriptLibData; - } - - if (gScriptLibrary.mFunctions[arg].mArgs) - { - number = (S32)strlen(gScriptLibrary.mFunctions[arg].mArgs); /*Flawfinder: ignore*/ - arguments = new LLScriptLibData[number]; - } - else - { - number = 0; - } - - for (i = number - 1; i >= 0; i--) - { - lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg].mArgs[i]); - } - - if (b_print) - { - printf("See LSLTipText_%s in strings.xml for usage\n", gScriptLibrary.mFunctions[arg].mName); - } - - { - gScriptLibrary.mFunctions[arg].mExecFunc(returnvalue, arguments, id); + printf("[0x%X]\tCALLLIB ", offset); + LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg]; + printf("%d (%s)\n", (U32)arg, function.mName); + //printf("%s\n", function.mDesc); } - add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg].mEnergyUse); - add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg].mSleepTime); + return run_calllib_common(buffer, offset, id, arg); +} - if (returnvalue) +BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) +{ + offset++; + U16 arg = safe_instruction_bytestream2u16(buffer, offset); + if (b_print && + arg < gScriptLibrary.mFunctions.size()) { - returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg].mReturnType); - lscript_push_return_variable(returnvalue, buffer); + printf("[0x%X]\tCALLLIB ", (offset-1)); + LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg]; + printf("%d (%s)\n", (U32)arg, function.mName); + //printf("%s\n", function.mDesc); } - - delete [] arguments; - delete returnvalue; - - // reset the BP after calling the library files - S32 bp = lscript_pop_int(buffer); - set_bp(buffer, bp); - - // pop off the spot for the instruction pointer - lscript_poparg(buffer, 4); - return FALSE; + return run_calllib_common(buffer, offset, id, arg); } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 14a37981a6..e0ca0a760f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -187,6 +187,7 @@ set(viewer_SOURCE_FILES llfloaternotificationsconsole.cpp llfloateropenobject.cpp llfloaterparcel.cpp + llfloaterpay.cpp llfloaterperms.cpp llfloaterpostcard.cpp llfloaterpostprocess.cpp @@ -218,7 +219,6 @@ set(viewer_SOURCE_FILES llfollowcam.cpp llfriendcard.cpp llgesturemgr.cpp - llgivemoney.cpp llglsandbox.cpp llgroupactions.cpp llgrouplist.cpp @@ -264,8 +264,7 @@ set(viewer_SOURCE_FILES llmaniptranslate.cpp llmapresponders.cpp llmediactrl.cpp - llmediadataresponder.cpp - llmediadatafetcher.cpp + llmediadataclient.cpp llmediaremotectrl.cpp llmemoryview.cpp llmenucommands.cpp @@ -659,6 +658,7 @@ set(viewer_HEADER_FILES llfloaternotificationsconsole.h llfloateropenobject.h llfloaterparcel.h + llfloaterpay.h llfloaterpostcard.h llfloaterpostprocess.h llfloaterpreference.h @@ -691,7 +691,6 @@ set(viewer_HEADER_FILES llfollowcam.h llfriendcard.h llgesturemgr.h - llgivemoney.h llgroupactions.h llgrouplist.h llgroupmgr.h @@ -735,8 +734,7 @@ set(viewer_HEADER_FILES llmanipscale.h llmaniptranslate.h llmapresponders.h - llmediadataresponder.h - llmediadatafetcher.h + llmediadataclient.h llmediaremotectrl.h llmemoryview.h llmenucommands.h @@ -1105,14 +1103,10 @@ if (WINDOWS) res/ll_icon.BMP res/ll_icon.ico res/resource.h - res/toolbuy.cur - res/toolopen.cur - res/toolpay.cur res/toolpickobject.cur res/toolpickobject2.cur res/toolpickobject3.cur res/toolpipette.cur - res/toolsit.cur ) set_source_files_properties(${viewer_RESOURCE_FILES} @@ -1546,6 +1540,7 @@ include(LLAddBuildTest) SET(viewer_TEST_SOURCE_FILES llagentaccess.cpp lldateutil.cpp + llmediadataclient.cpp llviewerhelputil.cpp ) set_source_files_properties( @@ -1563,6 +1558,7 @@ set(test_libs ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} ) LL_ADD_INTEGRATION_TEST(llcapabilitylistener diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings index 735424c647..0e685c818a 100644 --- a/indra/newview/English.lproj/InfoPlist.strings +++ b/indra/newview/English.lproj/InfoPlist.strings @@ -2,6 +2,6 @@ CFBundleName = "Second Life"; -CFBundleShortVersionString = "Second Life version 2.0.0.0"; -CFBundleGetInfoString = "Second Life version 2.0.0.0, Copyright 2004-2009 Linden Research, Inc."; +CFBundleShortVersionString = "Second Life version 2.0.0.2639"; +CFBundleGetInfoString = "Second Life version 2.0.0.2639, Copyright 2004-2009 Linden Research, Inc."; diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index 7264044d37..0c1d6ea105 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -32,7 +32,7 @@ </dict> </array> <key>CFBundleVersion</key> - <string>2.0.0.0</string> + <string>2.0.0.2639</string> <key>CSResourcesFileMapped</key> <true/> </dict> diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index a49ccb77b4..0524834747 100644 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -25,6 +25,7 @@ <string>AppCache</string> <string>Window</string> <string>RenderInit</string> + <string>MediaOnAPrim</string> </array> </map> <map> @@ -40,7 +41,6 @@ </array> <key>tags</key> <array> - <string>ShaderLoading</string> </array> </map> </array> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 94a5f5c52b..dc0e5ffa1d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5294,7 +5294,18 @@ <key>Value</key> <integer>13</integer> </map> - <key>PrimMediaFetchQueueDelay</key> + <key>PrimMediaMaxRetries</key> + <map> + <key>Comment</key> + <string>Maximum number of retries for media queries.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>4</integer> + </map> + <key>PrimMediaRequestQueueDelay</key> <map> <key>Comment</key> <string>Timer delay for fetching media from the queue (in seconds).</string> @@ -6117,6 +6128,18 @@ <real>1.0</real> </map> + <key>RenderHighlightEnable</key> + <map> + <key>Comment</key> + <string>Show glow effect when hovering on interactive objects.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>RenderHighlightFadeTime</key> <map> <key>Comment</key> diff --git a/indra/newview/character/avatar_eye.llm b/indra/newview/character/avatar_eye.llm Binary files differnew file mode 100644 index 0000000000..8c6e74e1de --- /dev/null +++ b/indra/newview/character/avatar_eye.llm diff --git a/indra/newview/character/avatar_eye_1.llm b/indra/newview/character/avatar_eye_1.llm Binary files differnew file mode 100644 index 0000000000..7a3b0d6f28 --- /dev/null +++ b/indra/newview/character/avatar_eye_1.llm diff --git a/indra/newview/character/avatar_eyelashes.llm b/indra/newview/character/avatar_eyelashes.llm Binary files differnew file mode 100644 index 0000000000..99995b5758 --- /dev/null +++ b/indra/newview/character/avatar_eyelashes.llm diff --git a/indra/newview/character/avatar_hair.llm b/indra/newview/character/avatar_hair.llm Binary files differnew file mode 100644 index 0000000000..df99de8db7 --- /dev/null +++ b/indra/newview/character/avatar_hair.llm diff --git a/indra/newview/character/avatar_hair_1.llm b/indra/newview/character/avatar_hair_1.llm Binary files differnew file mode 100644 index 0000000000..6de31fdc23 --- /dev/null +++ b/indra/newview/character/avatar_hair_1.llm diff --git a/indra/newview/character/avatar_hair_2.llm b/indra/newview/character/avatar_hair_2.llm Binary files differnew file mode 100644 index 0000000000..47d02ba9ce --- /dev/null +++ b/indra/newview/character/avatar_hair_2.llm diff --git a/indra/newview/character/avatar_hair_3.llm b/indra/newview/character/avatar_hair_3.llm Binary files differnew file mode 100644 index 0000000000..107f9e2a53 --- /dev/null +++ b/indra/newview/character/avatar_hair_3.llm diff --git a/indra/newview/character/avatar_hair_4.llm b/indra/newview/character/avatar_hair_4.llm Binary files differnew file mode 100644 index 0000000000..1b9a12a0ca --- /dev/null +++ b/indra/newview/character/avatar_hair_4.llm diff --git a/indra/newview/character/avatar_hair_5.llm b/indra/newview/character/avatar_hair_5.llm Binary files differnew file mode 100644 index 0000000000..1b9a12a0ca --- /dev/null +++ b/indra/newview/character/avatar_hair_5.llm diff --git a/indra/newview/character/avatar_head.llm b/indra/newview/character/avatar_head.llm Binary files differnew file mode 100644 index 0000000000..8d8b5e0442 --- /dev/null +++ b/indra/newview/character/avatar_head.llm diff --git a/indra/newview/character/avatar_head_1.llm b/indra/newview/character/avatar_head_1.llm Binary files differnew file mode 100644 index 0000000000..26291e6584 --- /dev/null +++ b/indra/newview/character/avatar_head_1.llm diff --git a/indra/newview/character/avatar_head_2.llm b/indra/newview/character/avatar_head_2.llm Binary files differnew file mode 100644 index 0000000000..c2b808b1a6 --- /dev/null +++ b/indra/newview/character/avatar_head_2.llm diff --git a/indra/newview/character/avatar_head_3.llm b/indra/newview/character/avatar_head_3.llm Binary files differnew file mode 100644 index 0000000000..a0676b1f1c --- /dev/null +++ b/indra/newview/character/avatar_head_3.llm diff --git a/indra/newview/character/avatar_head_4.llm b/indra/newview/character/avatar_head_4.llm Binary files differnew file mode 100644 index 0000000000..5035585770 --- /dev/null +++ b/indra/newview/character/avatar_head_4.llm diff --git a/indra/newview/character/avatar_lower_body.llm b/indra/newview/character/avatar_lower_body.llm Binary files differnew file mode 100644 index 0000000000..0420899739 --- /dev/null +++ b/indra/newview/character/avatar_lower_body.llm diff --git a/indra/newview/character/avatar_lower_body_1.llm b/indra/newview/character/avatar_lower_body_1.llm Binary files differnew file mode 100644 index 0000000000..1394eb848b --- /dev/null +++ b/indra/newview/character/avatar_lower_body_1.llm diff --git a/indra/newview/character/avatar_lower_body_2.llm b/indra/newview/character/avatar_lower_body_2.llm Binary files differnew file mode 100644 index 0000000000..0da9c1249e --- /dev/null +++ b/indra/newview/character/avatar_lower_body_2.llm diff --git a/indra/newview/character/avatar_lower_body_3.llm b/indra/newview/character/avatar_lower_body_3.llm Binary files differnew file mode 100644 index 0000000000..f3c49a1568 --- /dev/null +++ b/indra/newview/character/avatar_lower_body_3.llm diff --git a/indra/newview/character/avatar_lower_body_4.llm b/indra/newview/character/avatar_lower_body_4.llm Binary files differnew file mode 100644 index 0000000000..e71721063e --- /dev/null +++ b/indra/newview/character/avatar_lower_body_4.llm diff --git a/indra/newview/character/avatar_skirt.llm b/indra/newview/character/avatar_skirt.llm Binary files differnew file mode 100644 index 0000000000..08ce3d1700 --- /dev/null +++ b/indra/newview/character/avatar_skirt.llm diff --git a/indra/newview/character/avatar_skirt_1.llm b/indra/newview/character/avatar_skirt_1.llm Binary files differnew file mode 100644 index 0000000000..88076c321f --- /dev/null +++ b/indra/newview/character/avatar_skirt_1.llm diff --git a/indra/newview/character/avatar_skirt_2.llm b/indra/newview/character/avatar_skirt_2.llm Binary files differnew file mode 100644 index 0000000000..73b3effbc6 --- /dev/null +++ b/indra/newview/character/avatar_skirt_2.llm diff --git a/indra/newview/character/avatar_skirt_3.llm b/indra/newview/character/avatar_skirt_3.llm Binary files differnew file mode 100644 index 0000000000..ded546fdea --- /dev/null +++ b/indra/newview/character/avatar_skirt_3.llm diff --git a/indra/newview/character/avatar_skirt_4.llm b/indra/newview/character/avatar_skirt_4.llm Binary files differnew file mode 100644 index 0000000000..b9d5cb945e --- /dev/null +++ b/indra/newview/character/avatar_skirt_4.llm diff --git a/indra/newview/character/avatar_upper_body.llm b/indra/newview/character/avatar_upper_body.llm Binary files differnew file mode 100644 index 0000000000..da7d990540 --- /dev/null +++ b/indra/newview/character/avatar_upper_body.llm diff --git a/indra/newview/character/avatar_upper_body_1.llm b/indra/newview/character/avatar_upper_body_1.llm Binary files differnew file mode 100644 index 0000000000..31e104cc20 --- /dev/null +++ b/indra/newview/character/avatar_upper_body_1.llm diff --git a/indra/newview/character/avatar_upper_body_2.llm b/indra/newview/character/avatar_upper_body_2.llm Binary files differnew file mode 100644 index 0000000000..c1f4199b9c --- /dev/null +++ b/indra/newview/character/avatar_upper_body_2.llm diff --git a/indra/newview/character/avatar_upper_body_3.llm b/indra/newview/character/avatar_upper_body_3.llm Binary files differnew file mode 100644 index 0000000000..9e89ed8b3e --- /dev/null +++ b/indra/newview/character/avatar_upper_body_3.llm diff --git a/indra/newview/character/avatar_upper_body_4.llm b/indra/newview/character/avatar_upper_body_4.llm Binary files differnew file mode 100644 index 0000000000..ec836d1dc3 --- /dev/null +++ b/indra/newview/character/avatar_upper_body_4.llm diff --git a/indra/newview/character/blush_alpha.tga b/indra/newview/character/blush_alpha.tga Binary files differnew file mode 100644 index 0000000000..05be7e7e3d --- /dev/null +++ b/indra/newview/character/blush_alpha.tga diff --git a/indra/newview/character/body_skingrain.tga b/indra/newview/character/body_skingrain.tga Binary files differnew file mode 100644 index 0000000000..7264baac14 --- /dev/null +++ b/indra/newview/character/body_skingrain.tga diff --git a/indra/newview/character/bodyfreckles_alpha.tga b/indra/newview/character/bodyfreckles_alpha.tga Binary files differnew file mode 100644 index 0000000000..d30ab3d122 --- /dev/null +++ b/indra/newview/character/bodyfreckles_alpha.tga diff --git a/indra/newview/character/bump_face_wrinkles.tga b/indra/newview/character/bump_face_wrinkles.tga Binary files differnew file mode 100644 index 0000000000..54bf7a55be --- /dev/null +++ b/indra/newview/character/bump_face_wrinkles.tga diff --git a/indra/newview/character/bump_head_base.tga b/indra/newview/character/bump_head_base.tga Binary files differnew file mode 100644 index 0000000000..fa3568573a --- /dev/null +++ b/indra/newview/character/bump_head_base.tga diff --git a/indra/newview/character/bump_lowerbody_base.tga b/indra/newview/character/bump_lowerbody_base.tga Binary files differnew file mode 100644 index 0000000000..498ea3c721 --- /dev/null +++ b/indra/newview/character/bump_lowerbody_base.tga diff --git a/indra/newview/character/bump_pants_wrinkles.tga b/indra/newview/character/bump_pants_wrinkles.tga Binary files differnew file mode 100644 index 0000000000..cca72415e8 --- /dev/null +++ b/indra/newview/character/bump_pants_wrinkles.tga diff --git a/indra/newview/character/bump_shirt_wrinkles.tga b/indra/newview/character/bump_shirt_wrinkles.tga Binary files differnew file mode 100644 index 0000000000..9e0d757a48 --- /dev/null +++ b/indra/newview/character/bump_shirt_wrinkles.tga diff --git a/indra/newview/character/bump_upperbody_base.tga b/indra/newview/character/bump_upperbody_base.tga Binary files differnew file mode 100644 index 0000000000..e57d6352e6 --- /dev/null +++ b/indra/newview/character/bump_upperbody_base.tga diff --git a/indra/newview/character/eyebrows_alpha.tga b/indra/newview/character/eyebrows_alpha.tga Binary files differnew file mode 100644 index 0000000000..c363e482e1 --- /dev/null +++ b/indra/newview/character/eyebrows_alpha.tga diff --git a/indra/newview/character/eyeliner_alpha.tga b/indra/newview/character/eyeliner_alpha.tga Binary files differnew file mode 100644 index 0000000000..1611eb3355 --- /dev/null +++ b/indra/newview/character/eyeliner_alpha.tga diff --git a/indra/newview/character/eyeshadow_inner_alpha.tga b/indra/newview/character/eyeshadow_inner_alpha.tga Binary files differnew file mode 100644 index 0000000000..37d7919395 --- /dev/null +++ b/indra/newview/character/eyeshadow_inner_alpha.tga diff --git a/indra/newview/character/eyeshadow_outer_alpha.tga b/indra/newview/character/eyeshadow_outer_alpha.tga Binary files differnew file mode 100644 index 0000000000..00eef9d9f7 --- /dev/null +++ b/indra/newview/character/eyeshadow_outer_alpha.tga diff --git a/indra/newview/character/eyewhite.tga b/indra/newview/character/eyewhite.tga Binary files differnew file mode 100644 index 0000000000..a720496988 --- /dev/null +++ b/indra/newview/character/eyewhite.tga diff --git a/indra/newview/character/facehair_chincurtains_alpha.tga b/indra/newview/character/facehair_chincurtains_alpha.tga Binary files differnew file mode 100644 index 0000000000..b10397063c --- /dev/null +++ b/indra/newview/character/facehair_chincurtains_alpha.tga diff --git a/indra/newview/character/facehair_moustache_alpha.tga b/indra/newview/character/facehair_moustache_alpha.tga Binary files differnew file mode 100644 index 0000000000..4068c4f2b1 --- /dev/null +++ b/indra/newview/character/facehair_moustache_alpha.tga diff --git a/indra/newview/character/facehair_sideburns_alpha.tga b/indra/newview/character/facehair_sideburns_alpha.tga Binary files differnew file mode 100644 index 0000000000..acddc2d9bd --- /dev/null +++ b/indra/newview/character/facehair_sideburns_alpha.tga diff --git a/indra/newview/character/facehair_soulpatch_alpha.tga b/indra/newview/character/facehair_soulpatch_alpha.tga Binary files differnew file mode 100644 index 0000000000..687091a29f --- /dev/null +++ b/indra/newview/character/facehair_soulpatch_alpha.tga diff --git a/indra/newview/character/freckles_alpha.tga b/indra/newview/character/freckles_alpha.tga Binary files differnew file mode 100644 index 0000000000..a9a4ec0735 --- /dev/null +++ b/indra/newview/character/freckles_alpha.tga diff --git a/indra/newview/character/glove_length_alpha.tga b/indra/newview/character/glove_length_alpha.tga Binary files differnew file mode 100644 index 0000000000..db89ad57e7 --- /dev/null +++ b/indra/newview/character/glove_length_alpha.tga diff --git a/indra/newview/character/gloves_fingers_alpha.tga b/indra/newview/character/gloves_fingers_alpha.tga Binary files differnew file mode 100644 index 0000000000..dba2eec277 --- /dev/null +++ b/indra/newview/character/gloves_fingers_alpha.tga diff --git a/indra/newview/character/head_alpha.tga b/indra/newview/character/head_alpha.tga Binary files differnew file mode 100644 index 0000000000..8164525353 --- /dev/null +++ b/indra/newview/character/head_alpha.tga diff --git a/indra/newview/character/head_color.tga b/indra/newview/character/head_color.tga Binary files differnew file mode 100644 index 0000000000..74b1b3078b --- /dev/null +++ b/indra/newview/character/head_color.tga diff --git a/indra/newview/character/head_hair.tga b/indra/newview/character/head_hair.tga Binary files differnew file mode 100644 index 0000000000..5321f35204 --- /dev/null +++ b/indra/newview/character/head_hair.tga diff --git a/indra/newview/character/head_highlights_alpha.tga b/indra/newview/character/head_highlights_alpha.tga Binary files differnew file mode 100644 index 0000000000..8dc5239f97 --- /dev/null +++ b/indra/newview/character/head_highlights_alpha.tga diff --git a/indra/newview/character/head_shading_alpha.tga b/indra/newview/character/head_shading_alpha.tga Binary files differnew file mode 100644 index 0000000000..e8ea490109 --- /dev/null +++ b/indra/newview/character/head_shading_alpha.tga diff --git a/indra/newview/character/head_skingrain.tga b/indra/newview/character/head_skingrain.tga Binary files differnew file mode 100644 index 0000000000..b42dee0809 --- /dev/null +++ b/indra/newview/character/head_skingrain.tga diff --git a/indra/newview/character/jacket_length_lower_alpha.tga b/indra/newview/character/jacket_length_lower_alpha.tga Binary files differnew file mode 100644 index 0000000000..722bc192a8 --- /dev/null +++ b/indra/newview/character/jacket_length_lower_alpha.tga diff --git a/indra/newview/character/jacket_length_upper_alpha.tga b/indra/newview/character/jacket_length_upper_alpha.tga Binary files differnew file mode 100644 index 0000000000..e9db7e7b1f --- /dev/null +++ b/indra/newview/character/jacket_length_upper_alpha.tga diff --git a/indra/newview/character/jacket_open_lower_alpha.tga b/indra/newview/character/jacket_open_lower_alpha.tga Binary files differnew file mode 100644 index 0000000000..db0c2fb0e3 --- /dev/null +++ b/indra/newview/character/jacket_open_lower_alpha.tga diff --git a/indra/newview/character/jacket_open_upper_alpha.tga b/indra/newview/character/jacket_open_upper_alpha.tga Binary files differnew file mode 100644 index 0000000000..71b8a0b805 --- /dev/null +++ b/indra/newview/character/jacket_open_upper_alpha.tga diff --git a/indra/newview/character/lipgloss_alpha.tga b/indra/newview/character/lipgloss_alpha.tga Binary files differnew file mode 100644 index 0000000000..78ceecaf85 --- /dev/null +++ b/indra/newview/character/lipgloss_alpha.tga diff --git a/indra/newview/character/lips_mask.tga b/indra/newview/character/lips_mask.tga Binary files differnew file mode 100644 index 0000000000..ae1401c006 --- /dev/null +++ b/indra/newview/character/lips_mask.tga diff --git a/indra/newview/character/lipstick_alpha.tga b/indra/newview/character/lipstick_alpha.tga Binary files differnew file mode 100644 index 0000000000..2795f1bd40 --- /dev/null +++ b/indra/newview/character/lipstick_alpha.tga diff --git a/indra/newview/character/lowerbody_color.tga b/indra/newview/character/lowerbody_color.tga Binary files differnew file mode 100644 index 0000000000..a63aa12fca --- /dev/null +++ b/indra/newview/character/lowerbody_color.tga diff --git a/indra/newview/character/lowerbody_highlights_alpha.tga b/indra/newview/character/lowerbody_highlights_alpha.tga Binary files differnew file mode 100644 index 0000000000..ae3413ac8b --- /dev/null +++ b/indra/newview/character/lowerbody_highlights_alpha.tga diff --git a/indra/newview/character/lowerbody_shading_alpha.tga b/indra/newview/character/lowerbody_shading_alpha.tga Binary files differnew file mode 100644 index 0000000000..0242663a7d --- /dev/null +++ b/indra/newview/character/lowerbody_shading_alpha.tga diff --git a/indra/newview/character/nailpolish_alpha.tga b/indra/newview/character/nailpolish_alpha.tga Binary files differnew file mode 100644 index 0000000000..91af762902 --- /dev/null +++ b/indra/newview/character/nailpolish_alpha.tga diff --git a/indra/newview/character/pants_length_alpha.tga b/indra/newview/character/pants_length_alpha.tga Binary files differnew file mode 100644 index 0000000000..3c4f21c0f2 --- /dev/null +++ b/indra/newview/character/pants_length_alpha.tga diff --git a/indra/newview/character/pants_waist_alpha.tga b/indra/newview/character/pants_waist_alpha.tga Binary files differnew file mode 100644 index 0000000000..35658c0896 --- /dev/null +++ b/indra/newview/character/pants_waist_alpha.tga diff --git a/indra/newview/character/rosyface_alpha.tga b/indra/newview/character/rosyface_alpha.tga Binary files differnew file mode 100644 index 0000000000..a0c8513da2 --- /dev/null +++ b/indra/newview/character/rosyface_alpha.tga diff --git a/indra/newview/character/rouge_alpha.tga b/indra/newview/character/rouge_alpha.tga Binary files differnew file mode 100644 index 0000000000..a0c8513da2 --- /dev/null +++ b/indra/newview/character/rouge_alpha.tga diff --git a/indra/newview/character/shirt_bottom_alpha.tga b/indra/newview/character/shirt_bottom_alpha.tga Binary files differnew file mode 100644 index 0000000000..7cce03dbe0 --- /dev/null +++ b/indra/newview/character/shirt_bottom_alpha.tga diff --git a/indra/newview/character/shirt_collar_alpha.tga b/indra/newview/character/shirt_collar_alpha.tga Binary files differnew file mode 100644 index 0000000000..f55f635473 --- /dev/null +++ b/indra/newview/character/shirt_collar_alpha.tga diff --git a/indra/newview/character/shirt_collar_back_alpha.tga b/indra/newview/character/shirt_collar_back_alpha.tga Binary files differnew file mode 100644 index 0000000000..43a6453107 --- /dev/null +++ b/indra/newview/character/shirt_collar_back_alpha.tga diff --git a/indra/newview/character/shirt_sleeve_alpha.tga b/indra/newview/character/shirt_sleeve_alpha.tga Binary files differnew file mode 100644 index 0000000000..e3b18f4fc6 --- /dev/null +++ b/indra/newview/character/shirt_sleeve_alpha.tga diff --git a/indra/newview/character/shoe_height_alpha.tga b/indra/newview/character/shoe_height_alpha.tga Binary files differnew file mode 100644 index 0000000000..d08dd750f3 --- /dev/null +++ b/indra/newview/character/shoe_height_alpha.tga diff --git a/indra/newview/character/skirt_length_alpha.tga b/indra/newview/character/skirt_length_alpha.tga Binary files differnew file mode 100644 index 0000000000..c86799469d --- /dev/null +++ b/indra/newview/character/skirt_length_alpha.tga diff --git a/indra/newview/character/skirt_slit_back_alpha.tga b/indra/newview/character/skirt_slit_back_alpha.tga Binary files differnew file mode 100644 index 0000000000..0e49688b14 --- /dev/null +++ b/indra/newview/character/skirt_slit_back_alpha.tga diff --git a/indra/newview/character/skirt_slit_front_alpha.tga b/indra/newview/character/skirt_slit_front_alpha.tga Binary files differnew file mode 100644 index 0000000000..888bbf71a1 --- /dev/null +++ b/indra/newview/character/skirt_slit_front_alpha.tga diff --git a/indra/newview/character/skirt_slit_left_alpha.tga b/indra/newview/character/skirt_slit_left_alpha.tga Binary files differnew file mode 100644 index 0000000000..210feac1ea --- /dev/null +++ b/indra/newview/character/skirt_slit_left_alpha.tga diff --git a/indra/newview/character/skirt_slit_right_alpha.tga b/indra/newview/character/skirt_slit_right_alpha.tga Binary files differnew file mode 100644 index 0000000000..ce11c64bf6 --- /dev/null +++ b/indra/newview/character/skirt_slit_right_alpha.tga diff --git a/indra/newview/character/underpants_trial_female.tga b/indra/newview/character/underpants_trial_female.tga Binary files differnew file mode 100644 index 0000000000..96bf732351 --- /dev/null +++ b/indra/newview/character/underpants_trial_female.tga diff --git a/indra/newview/character/underpants_trial_male.tga b/indra/newview/character/underpants_trial_male.tga Binary files differnew file mode 100644 index 0000000000..095695ca1c --- /dev/null +++ b/indra/newview/character/underpants_trial_male.tga diff --git a/indra/newview/character/undershirt_trial_female.tga b/indra/newview/character/undershirt_trial_female.tga Binary files differnew file mode 100644 index 0000000000..e17a309531 --- /dev/null +++ b/indra/newview/character/undershirt_trial_female.tga diff --git a/indra/newview/character/upperbody_color.tga b/indra/newview/character/upperbody_color.tga Binary files differnew file mode 100644 index 0000000000..85fcc41142 --- /dev/null +++ b/indra/newview/character/upperbody_color.tga diff --git a/indra/newview/character/upperbody_highlights_alpha.tga b/indra/newview/character/upperbody_highlights_alpha.tga Binary files differnew file mode 100644 index 0000000000..2d8102b583 --- /dev/null +++ b/indra/newview/character/upperbody_highlights_alpha.tga diff --git a/indra/newview/character/upperbody_shading_alpha.tga b/indra/newview/character/upperbody_shading_alpha.tga Binary files differnew file mode 100644 index 0000000000..b420506b3e --- /dev/null +++ b/indra/newview/character/upperbody_shading_alpha.tga diff --git a/indra/newview/character/upperbodyfreckles_alpha.tga b/indra/newview/character/upperbodyfreckles_alpha.tga Binary files differnew file mode 100644 index 0000000000..76c7ce8849 --- /dev/null +++ b/indra/newview/character/upperbodyfreckles_alpha.tga diff --git a/indra/newview/cursors_mac/UI_CURSOR_TOOLBUY.tif b/indra/newview/cursors_mac/UI_CURSOR_TOOLBUY.tif Binary files differdeleted file mode 100644 index 39d89987aa..0000000000 --- a/indra/newview/cursors_mac/UI_CURSOR_TOOLBUY.tif +++ /dev/null diff --git a/indra/newview/cursors_mac/UI_CURSOR_TOOLOPEN.tif b/indra/newview/cursors_mac/UI_CURSOR_TOOLOPEN.tif Binary files differdeleted file mode 100644 index 864c8dee7a..0000000000 --- a/indra/newview/cursors_mac/UI_CURSOR_TOOLOPEN.tif +++ /dev/null diff --git a/indra/newview/cursors_mac/UI_CURSOR_TOOLSIT.tif b/indra/newview/cursors_mac/UI_CURSOR_TOOLSIT.tif Binary files differdeleted file mode 100644 index d6d835a90b..0000000000 --- a/indra/newview/cursors_mac/UI_CURSOR_TOOLSIT.tif +++ /dev/null diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 92b2768f39..2b5e2369bb 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -48,7 +48,7 @@ #include "llfloatergroupinvite.h" #include "llfloatergroups.h" #include "llfloaterreg.h" -#include "llgivemoney.h" +#include "llfloaterpay.h" #include "llinventorymodel.h" // for gInventory.findCategoryUUIDForType #include "llimview.h" // for gIMMgr #include "llmutelist.h" @@ -306,7 +306,7 @@ bool LLAvatarActions::handlePay(const LLSD& notification, const LLSD& response, gAgent.clearBusy(); } - LLFloaterPay::payDirectly(&give_money, avatar_id, /*is_group=*/FALSE); + LLFloaterPayUtil::payDirectly(&give_money, avatar_id, /*is_group=*/false); return false; } diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 28c124d1c6..2467356018 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -45,7 +45,7 @@ public: : LLTextSegment(start, end), mEditor(editor), mStyle(style), - mMoreText(more_text) + mExpanderLabel(more_text) {} /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const @@ -61,7 +61,15 @@ public: /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { F32 right_x; - mStyle->getFont()->renderUTF8(mMoreText, start, draw_rect.mRight, draw_rect.mTop, mStyle->getColor(), LLFontGL::RIGHT, LLFontGL::TOP, 0, mStyle->getShadowType(), end - start, draw_rect.getWidth(), &right_x, mEditor.getUseEllipses()); + mStyle->getFont()->renderUTF8(mExpanderLabel, start, + draw_rect.mRight, draw_rect.mTop, + mStyle->getColor(), + LLFontGL::RIGHT, LLFontGL::TOP, + 0, + mStyle->getShadowType(), + end - start, draw_rect.getWidth(), + &right_x, + mEditor.getUseEllipses()); return right_x; } /*virtual*/ S32 getMaxHeight() const { return llceil(mStyle->getFont()->getLineHeight()); } @@ -75,14 +83,17 @@ public: private: LLTextBase& mEditor; LLStyleSP mStyle; - std::string mMoreText; + std::string mExpanderLabel; }; - +LLExpandableTextBox::LLTextBoxEx::Params::Params() +: more_label("more_label") +{} LLExpandableTextBox::LLTextBoxEx::LLTextBoxEx(const Params& p) : LLTextBox(p), - mExpanded(false) + mExpanderLabel(p.more_label), + mExpanderVisible(false) { setIsChrome(TRUE); @@ -106,6 +117,9 @@ void LLExpandableTextBox::LLTextBoxEx::setValue(const LLSD& value) { LLTextBox::setValue(value); + // text contents have changed, segments are cleared out + // so hide the expander and determine if we need it + //mExpanderVisible = false; if (getTextPixelHeight() > getRect().getHeight()) { showExpandText(); @@ -119,7 +133,7 @@ void LLExpandableTextBox::LLTextBoxEx::setValue(const LLSD& value) void LLExpandableTextBox::LLTextBoxEx::showExpandText() { - if (!mExpanded) + if (!mExpanderVisible) { // get fully visible lines std::pair<S32, S32> visible_lines = getVisibleLines(true); @@ -129,9 +143,9 @@ void LLExpandableTextBox::LLTextBoxEx::showExpandText() expander_style.font.name.setIfNotProvided(LLFontGL::nameFromFont(expander_style.font)); expander_style.font.style = "UNDERLINE"; expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, "More", *this); + LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this); insertSegment(expanderp); - mExpanded = true; + mExpanderVisible = true; } } @@ -139,14 +153,14 @@ void LLExpandableTextBox::LLTextBoxEx::showExpandText() //NOTE: obliterates existing styles (including hyperlinks) void LLExpandableTextBox::LLTextBoxEx::hideExpandText() { - if (mExpanded) + if (mExpanderVisible) { // this will overwrite the expander segment and all text styling with a single style LLNormalTextSegment* segmentp = new LLNormalTextSegment( new LLStyle(getDefaultStyle()), 0, getLength() + 1, *this); insertSegment(segmentp); - mExpanded = false; + mExpanderVisible = false; } } @@ -275,6 +289,9 @@ S32 LLExpandableTextBox::recalculateTextDelta(S32 text_delta) void LLExpandableTextBox::expandTextBox() { + // hide "more" link, and show full text contents + mTextBox->hideExpandText(); + S32 text_delta = mTextBox->getVerticalTextDelta(); text_delta += mTextBox->getVPad() * 2 + mScroll->getBorderWidth() * 2; // no need to expand diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h index b78a4dc674..d6401e224f 100644 --- a/indra/newview/llexpandabletextbox.h +++ b/indra/newview/llexpandabletextbox.h @@ -54,6 +54,8 @@ protected: public: struct Params : public LLInitParam::Block<Params, LLTextBox::Params> { + Mandatory<std::string> more_label; + Params(); }; // adds or removes "More" link as needed @@ -76,11 +78,6 @@ protected: */ virtual S32 getHPad() { return mHPad; } - protected: - - LLTextBoxEx(const Params& p); - friend class LLUICtrlFactory; - /** * Shows "More" link */ @@ -91,9 +88,15 @@ protected: */ void hideExpandText(); + protected: + + LLTextBoxEx(const Params& p); + friend class LLUICtrlFactory; + private: + std::string mExpanderLabel; - bool mExpanded; + bool mExpanderVisible; }; public: diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 91b9bcfe72..890d863db7 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -37,20 +37,15 @@ #include "llagent.h" #include "llfocusmgr.h" #include "llfloaterreg.h" -#include "llfloaterinventory.h" -#include "llfoldervieweventlistener.h" -#include "llinventorymodel.h" #include "llviewercontrol.h" #include "llworld.h" // Linden libraries -#include "llbutton.h" #include "lllineeditor.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llscrolllistcell.h" #include "lltabcontainer.h" -#include "lltextbox.h" #include "lluictrlfactory.h" #include "message.h" @@ -117,13 +112,6 @@ BOOL LLFloaterAvatarPicker::postBuild() getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("no_results")); - LLInventoryPanel* inventory_panel = getChild<LLInventoryPanel>("InventoryPanel"); - inventory_panel->setFilterTypes(0x1 << LLInventoryType::IT_CALLINGCARD); - inventory_panel->setFollowsAll(); - inventory_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - inventory_panel->openDefaultFolderForType(LLAssetType::AT_CALLINGCARD); - inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::doCallingCardSelectionChange, this, _1, _2)); - getChild<LLTabContainer>("ResidentChooserTabs")->setCommitCallback( boost::bind(&LLFloaterAvatarPicker::onTabChanged, this)); @@ -173,11 +161,7 @@ void LLFloaterAvatarPicker::onBtnSelect(void* userdata) { LLPanel* active_panel = self->childGetVisibleTab("ResidentChooserTabs"); - if(active_panel == self->getChild<LLPanel>("CallingCardsPanel")) - { - self->mCallback(self->mSelectedInventoryAvatarNames, self->mSelectedInventoryAvatarIDs, self->mCallbackUserdata); - } - else if(active_panel == self->getChild<LLPanel>("SearchPanel")) + if(active_panel == self->getChild<LLPanel>("SearchPanel")) { std::vector<std::string> avatar_names; std::vector<LLUUID> avatar_ids; @@ -192,7 +176,6 @@ void LLFloaterAvatarPicker::onBtnSelect(void* userdata) self->mCallback(avatar_names, avatar_ids, self->mCallbackUserdata); } } - self->getChild<LLInventoryPanel>("InventoryPanel")->setSelection(LLUUID::null, FALSE); self->getChild<LLScrollListCtrl>("SearchResults")->deselectAllItems(TRUE); self->getChild<LLScrollListCtrl>("NearMe")->deselectAllItems(TRUE); if(self->mCloseOnSelect) @@ -235,40 +218,6 @@ void LLFloaterAvatarPicker::onList(LLUICtrl* ctrl, void* userdata) } } -// Callback for inventory picker (select from calling cards) -void LLFloaterAvatarPicker::doCallingCardSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) -{ - bool panel_active = (childGetVisibleTab("ResidentChooserTabs") == getChild<LLPanel>("CallingCardsPanel")); - - mSelectedInventoryAvatarIDs.clear(); - mSelectedInventoryAvatarNames.clear(); - - if (panel_active) - { - childSetEnabled("Select", FALSE); - } - - std::deque<LLFolderViewItem*>::const_iterator item_it; - for (item_it = items.begin(); item_it != items.end(); ++item_it) - { - LLFolderViewEventListener* listenerp = (*item_it)->getListener(); - if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) - { - LLInventoryItem* item = gInventory.getItem(listenerp->getUUID()); - if (item) - { - mSelectedInventoryAvatarIDs.push_back(item->getCreatorUUID()); - mSelectedInventoryAvatarNames.push_back(listenerp->getName()); - } - } - } - - if (panel_active) - { - childSetEnabled("Select", visibleItemsSelected()); - } -} - void LLFloaterAvatarPicker::populateNearMe() { BOOL all_loaded = TRUE; @@ -336,10 +285,6 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const { return getChild<LLScrollListCtrl>("SearchResults")->getFirstSelectedIndex() >= 0; } - else if(active_panel == getChild<LLPanel>("CallingCardsPanel")) - { - return mSelectedInventoryAvatarIDs.size() > 0; - } else if(active_panel == getChild<LLPanel>("NearMePanel")) { return getChild<LLScrollListCtrl>("NearMe")->getFirstSelectedIndex() >= 0; @@ -349,7 +294,7 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const void LLFloaterAvatarPicker::find() { - const std::string& text = childGetValue("Edit").asString(); + std::string text = childGetValue("Edit").asString(); mQueryID.generate(); @@ -375,7 +320,6 @@ void LLFloaterAvatarPicker::find() void LLFloaterAvatarPicker::setAllowMultiple(BOOL allow_multiple) { getChild<LLScrollListCtrl>("SearchResults")->setAllowMultipleSelection(allow_multiple); - getChild<LLInventoryPanel>("InventoryPanel")->setAllowMultiSelect(allow_multiple); getChild<LLScrollListCtrl>("NearMe")->setAllowMultipleSelection(allow_multiple); } diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 63896bef9f..f3b9aefb9c 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -37,7 +37,6 @@ #include <vector> - class LLFloaterAvatarPicker : public LLFloater { public: @@ -57,7 +56,6 @@ public: static void processAvatarPickerReply(class LLMessageSystem* msg, void**); private: - static void editKeystroke(class LLLineEditor* caller, void* user_data); static void onBtnFind(void* userdata); @@ -68,8 +66,6 @@ private: static void onList(class LLUICtrl* ctrl, void* userdata); void onTabChanged(); - void doCallingCardSelectionChange(const std::deque<class LLFolderViewItem*> &items, BOOL user_action); - void populateNearMe(); BOOL visibleItemsSelected() const; // Returns true if any items in the current tab are selected. @@ -79,8 +75,6 @@ private: virtual void draw(); virtual BOOL handleKeyHere(KEY key, MASK mask); - std::vector<LLUUID> mSelectedInventoryAvatarIDs; - std::vector<std::string> mSelectedInventoryAvatarNames; LLUUID mQueryID; BOOL mResultsReturned; BOOL mNearMeListComplete; diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 473d5ce827..9d07362edc 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -74,8 +74,6 @@ BOOL LLFloaterBuy::postBuild() // mid-session and the saved rect is off-center. center(); - mCloseSignal.connect(boost::bind(&LLFloaterBuy::onClose, this)); - return TRUE; } @@ -310,7 +308,8 @@ void LLFloaterBuy::onClickCancel() closeFloater(); } -void LLFloaterBuy::onClose() +// virtual +void LLFloaterBuy::onClose(bool app_quitting) { mObjectSelection.clear(); } diff --git a/indra/newview/llfloaterbuy.h b/indra/newview/llfloaterbuy.h index 2ec66136b2..ab38e082dc 100644 --- a/indra/newview/llfloaterbuy.h +++ b/indra/newview/llfloaterbuy.h @@ -56,6 +56,7 @@ public: ~LLFloaterBuy(); /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); static void show(const LLSaleInfo& sale_info); @@ -70,7 +71,6 @@ protected: void onClickBuy(); void onClickCancel(); - void onClose(); private: LLSafeHandle<LLObjectSelection> mObjectSelection; diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index 6b0b5ed5e0..2e0ae3265e 100644 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -50,9 +50,6 @@ LLFloaterHelpBrowser::LLFloaterHelpBrowser(const LLSD& key) : LLFloater(key) { - // really really destroy the help browser when it's closed, it'll be recreated. - // *TODO: when onClose() is resurrected as a virtual, this bind can go away. - mCloseSignal.connect(boost::bind(&LLFloaterHelpBrowser::onClose, this)); } BOOL LLFloaterHelpBrowser::postBuild() @@ -79,8 +76,10 @@ void LLFloaterHelpBrowser::buildURLHistory() } } -void LLFloaterHelpBrowser::onClose() +//virtual +void LLFloaterHelpBrowser::onClose(bool app_quitting) { + // really really destroy the help browser when it's closed, it'll be recreated. destroy(); // really destroy this dialog on closure, it's relatively heavyweight. } diff --git a/indra/newview/llfloaterhelpbrowser.h b/indra/newview/llfloaterhelpbrowser.h index 14a276b428..b66a67c4d6 100644 --- a/indra/newview/llfloaterhelpbrowser.h +++ b/indra/newview/llfloaterhelpbrowser.h @@ -47,7 +47,7 @@ class LLFloaterHelpBrowser : LLFloaterHelpBrowser(const LLSD& key); /*virtual*/ BOOL postBuild(); - void onClose(); + /*virtual*/ void onClose(bool app_quitting); // inherited from LLViewerMediaObserver /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index 9b7f3305e5..5673550fbe 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -156,6 +156,8 @@ std::string LLFloaterMediaBrowser::getSupportURL() { return getString("support_page_url"); } + +//virtual void LLFloaterMediaBrowser::onClose(bool app_quitting) { //setVisible(FALSE); diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp index 811cc26efb..aa457de2d8 100644 --- a/indra/newview/llfloatermediasettings.cpp +++ b/indra/newview/llfloatermediasettings.cpp @@ -52,7 +52,10 @@ LLFloaterMediaSettings::LLFloaterMediaSettings(const LLSD& key) mPanelMediaSettingsGeneral(NULL), mPanelMediaSettingsSecurity(NULL), mPanelMediaSettingsPermissions(NULL), - mWaitingToClose( false ) + mWaitingToClose( false ), + mIdenticalHasMediaInfo( true ), + mMultipleMedia(false), + mMultipleValidMedia(false) { // LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_settings.xml"); } @@ -86,8 +89,6 @@ LLFloaterMediaSettings::~LLFloaterMediaSettings() // BOOL LLFloaterMediaSettings::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterMediaSettings::onClose, this)); - mApplyBtn = getChild<LLButton>("Apply"); mApplyBtn->setClickedCallback(onBtnApply, this); @@ -153,29 +154,29 @@ void LLFloaterMediaSettings::apply() } //////////////////////////////////////////////////////////////////////////////// -void LLFloaterMediaSettings::onClose() +void LLFloaterMediaSettings::onClose(bool app_quitting) { if(mPanelMediaSettingsGeneral) { - mPanelMediaSettingsGeneral->onClose(); + mPanelMediaSettingsGeneral->onClose(app_quitting); } LLFloaterReg::hideInstance("whitelist_entry"); } //////////////////////////////////////////////////////////////////////////////// //static -void LLFloaterMediaSettings::initValues( const LLSD& media_settings ) +void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable ) { - sInstance->clearValues(); + sInstance->clearValues(editable); // update all panels with values from simulator sInstance->mPanelMediaSettingsGeneral-> - initValues( sInstance->mPanelMediaSettingsGeneral, media_settings ); + initValues( sInstance->mPanelMediaSettingsGeneral, media_settings, editable ); sInstance->mPanelMediaSettingsSecurity-> - initValues( sInstance->mPanelMediaSettingsSecurity, media_settings ); + initValues( sInstance->mPanelMediaSettingsSecurity, media_settings, editable ); sInstance->mPanelMediaSettingsPermissions-> - initValues( sInstance->mPanelMediaSettingsPermissions, media_settings ); + initValues( sInstance->mPanelMediaSettingsPermissions, media_settings, editable ); } @@ -195,12 +196,12 @@ void LLFloaterMediaSettings::commitFields() //////////////////////////////////////////////////////////////////////////////// //static -void LLFloaterMediaSettings::clearValues() +void LLFloaterMediaSettings::clearValues( bool editable) { // clean up all panels before updating - sInstance->mPanelMediaSettingsGeneral->clearValues(sInstance->mPanelMediaSettingsGeneral); - sInstance->mPanelMediaSettingsSecurity->clearValues(sInstance->mPanelMediaSettingsSecurity); - sInstance->mPanelMediaSettingsPermissions->clearValues(sInstance->mPanelMediaSettingsPermissions); + sInstance->mPanelMediaSettingsGeneral ->clearValues(sInstance->mPanelMediaSettingsGeneral, editable); + sInstance->mPanelMediaSettingsSecurity ->clearValues(sInstance->mPanelMediaSettingsSecurity, editable); + sInstance->mPanelMediaSettingsPermissions->clearValues(sInstance->mPanelMediaSettingsPermissions, editable); } diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h index b95c590346..e2683039cc 100644 --- a/indra/newview/llfloatermediasettings.h +++ b/indra/newview/llfloatermediasettings.h @@ -47,14 +47,20 @@ public: LLFloaterMediaSettings(const LLSD& key); ~LLFloaterMediaSettings(); - virtual BOOL postBuild(); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + static LLFloaterMediaSettings* getInstance(); static void apply(); - static void initValues( const LLSD& media_settings ); - static void clearValues(); + static void initValues( const LLSD& media_settings , bool editable); + static void clearValues( bool editable); void enableOkApplyBtns( bool enable ); LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;}; + bool mIdenticalHasMediaInfo; + bool mMultipleMedia; + bool mMultipleValidMedia; + protected: LLButton *mOKBtn; LLButton *mCancelBtn; @@ -65,7 +71,7 @@ protected: LLPanelMediaSettingsSecurity* mPanelMediaSettingsSecurity; LLPanelMediaSettingsPermissions* mPanelMediaSettingsPermissions; - void onClose(); + static void onBtnOK(void*); static void onBtnCancel(void*); static void onBtnApply(void*); diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index 0df3780ac4..a61cc04941 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -63,7 +63,6 @@ protected: void refresh(); void draw(); virtual void onOpen(const LLSD& key); -// virtual void onClose(); void moveToInventory(bool wear); diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp new file mode 100644 index 0000000000..88811d06fe --- /dev/null +++ b/indra/newview/llfloaterpay.cpp @@ -0,0 +1,573 @@ +/** + * @file llfloaterpay.cpp + * @author Aaron Brashears, Kelly Washington, James Cook + * @brief Implementation of the LLFloaterPay class. + * + * $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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterpay.h" + +#include "message.h" +#include "llfloater.h" +#include "lllslconstants.h" // MAX_PAY_BUTTONS +#include "lluuid.h" + +#include "llagent.h" +#include "llfloaterreg.h" +#include "llresmgr.h" +#include "lltextbox.h" +#include "lllineeditor.h" +#include "llmutelist.h" +#include "llfloaterreporter.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llbutton.h" +#include "llselectmgr.h" +#include "lltransactiontypes.h" +#include "lluictrlfactory.h" + +///---------------------------------------------------------------------------- +/// Local function declarations, constants, enums, and typedefs +///---------------------------------------------------------------------------- + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLGiveMoneyInfo +// +// A small class used to track callback information +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFloaterPay; + +struct LLGiveMoneyInfo +{ + LLFloaterPay* mFloater; + S32 mAmount; + LLGiveMoneyInfo(LLFloaterPay* floater, S32 amount) : + mFloater(floater), mAmount(amount){} +}; + +///---------------------------------------------------------------------------- +/// Class LLFloaterPay +///---------------------------------------------------------------------------- + +class LLFloaterPay : public LLFloater +{ +public: + LLFloaterPay(const LLSD& key); + virtual ~LLFloaterPay(); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + + void setCallback(money_callback callback) { mCallback = callback; } + + + static void payViaObject(money_callback callback, LLSafeHandle<LLObjectSelection> selection); + + static void payDirectly(money_callback callback, + const LLUUID& target_id, + bool is_group); + +private: + static void onCancel(void* data); + static void onKeystroke(LLLineEditor* editor, void* data); + static void onGive(void* data); + void give(S32 amount); + static void processPayPriceReply(LLMessageSystem* msg, void **userdata); + void onCacheOwnerName(const LLUUID& owner_id, + const std::string& firstname, + const std::string& lastname, + BOOL is_group); + void finishPayUI(const LLUUID& target_id, BOOL is_group); + +protected: + std::vector<LLGiveMoneyInfo*> mCallbackData; + money_callback mCallback; + LLTextBox* mObjectNameText; + LLUUID mTargetUUID; + BOOL mTargetIsGroup; + BOOL mHaveName; + + LLButton* mQuickPayButton[MAX_PAY_BUTTONS]; + LLGiveMoneyInfo* mQuickPayInfo[MAX_PAY_BUTTONS]; + + LLSafeHandle<LLObjectSelection> mObjectSelection; + + static S32 sLastAmount; +}; + + +S32 LLFloaterPay::sLastAmount = 0; +const S32 MAX_AMOUNT_LENGTH = 10; +const S32 FASTPAY_BUTTON_WIDTH = 80; + +LLFloaterPay::LLFloaterPay(const LLSD& key) + : LLFloater(key), + mCallbackData(), + mCallback(NULL), + mObjectNameText(NULL), + mTargetUUID(key.asUUID()), + mTargetIsGroup(FALSE) +{ +} + +// Destroys the object +LLFloaterPay::~LLFloaterPay() +{ + std::for_each(mCallbackData.begin(), mCallbackData.end(), DeletePointer()); + // Name callbacks will be automatically disconnected since LLFloater is trackable +} + +BOOL LLFloaterPay::postBuild() +{ + S32 i = 0; + + LLGiveMoneyInfo* info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_0); + mCallbackData.push_back(info); + + childSetAction("fastpay 1",&LLFloaterPay::onGive,info); + childSetVisible("fastpay 1", FALSE); + + mQuickPayButton[i] = getChild<LLButton>("fastpay 1"); + mQuickPayInfo[i] = info; + ++i; + + info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_1); + mCallbackData.push_back(info); + + childSetAction("fastpay 5",&LLFloaterPay::onGive,info); + childSetVisible("fastpay 5", FALSE); + + mQuickPayButton[i] = getChild<LLButton>("fastpay 5"); + mQuickPayInfo[i] = info; + ++i; + + info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_2); + mCallbackData.push_back(info); + + childSetAction("fastpay 10",&LLFloaterPay::onGive,info); + childSetVisible("fastpay 10", FALSE); + + mQuickPayButton[i] = getChild<LLButton>("fastpay 10"); + mQuickPayInfo[i] = info; + ++i; + + info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_3); + mCallbackData.push_back(info); + + childSetAction("fastpay 20",&LLFloaterPay::onGive,info); + childSetVisible("fastpay 20", FALSE); + + mQuickPayButton[i] = getChild<LLButton>("fastpay 20"); + mQuickPayInfo[i] = info; + ++i; + + + childSetVisible("amount text", FALSE); + + std::string last_amount; + if(sLastAmount > 0) + { + last_amount = llformat("%d", sLastAmount); + } + + childSetVisible("amount", FALSE); + + getChild<LLLineEditor>("amount")->setKeystrokeCallback(&LLFloaterPay::onKeystroke, this); + childSetText("amount", last_amount); + childSetPrevalidate("amount", LLLineEditor::prevalidateNonNegativeS32); + + info = new LLGiveMoneyInfo(this, 0); + mCallbackData.push_back(info); + + childSetAction("pay btn",&LLFloaterPay::onGive,info); + setDefaultBtn("pay btn"); + childSetVisible("pay btn", FALSE); + childSetEnabled("pay btn", (sLastAmount > 0)); + + childSetAction("cancel btn",&LLFloaterPay::onCancel,this); + + return TRUE; +} + +// virtual +void LLFloaterPay::onClose(bool app_quitting) +{ + // Deselect the objects + mObjectSelection = NULL; +} + +// static +void LLFloaterPay::processPayPriceReply(LLMessageSystem* msg, void **userdata) +{ + LLFloaterPay* self = (LLFloaterPay*)userdata; + if (self) + { + S32 price; + LLUUID target; + + msg->getUUIDFast(_PREHASH_ObjectData,_PREHASH_ObjectID,target); + if (target != self->mTargetUUID) + { + // This is a message for a different object's pay info + return; + } + + msg->getS32Fast(_PREHASH_ObjectData,_PREHASH_DefaultPayPrice,price); + + if (PAY_PRICE_HIDE == price) + { + self->childSetVisible("amount", FALSE); + self->childSetVisible("pay btn", FALSE); + self->childSetVisible("amount text", FALSE); + } + else if (PAY_PRICE_DEFAULT == price) + { + self->childSetVisible("amount", TRUE); + self->childSetVisible("pay btn", TRUE); + self->childSetVisible("amount text", TRUE); + } + else + { + // PAY_PRICE_HIDE and PAY_PRICE_DEFAULT are negative values + // So we take the absolute value here after we have checked for those cases + + self->childSetVisible("amount", TRUE); + self->childSetVisible("pay btn", TRUE); + self->childSetEnabled("pay btn", TRUE); + self->childSetVisible("amount text", TRUE); + + self->childSetText("amount", llformat("%d", llabs(price))); + } + + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_ButtonData); + S32 i = 0; + if (num_blocks > MAX_PAY_BUTTONS) num_blocks = MAX_PAY_BUTTONS; + + S32 max_pay_amount = 0; + S32 padding_required = 0; + + for (i=0;i<num_blocks;++i) + { + S32 pay_button; + msg->getS32Fast(_PREHASH_ButtonData,_PREHASH_PayButton,pay_button,i); + if (pay_button > 0) + { + std::string button_str = "L$"; + button_str += LLResMgr::getInstance()->getMonetaryString( pay_button ); + + self->mQuickPayButton[i]->setLabelSelected(button_str); + self->mQuickPayButton[i]->setLabelUnselected(button_str); + self->mQuickPayButton[i]->setVisible(TRUE); + self->mQuickPayInfo[i]->mAmount = pay_button; + self->childSetVisible("fastpay text",TRUE); + + if ( pay_button > max_pay_amount ) + { + max_pay_amount = pay_button; + } + } + else + { + self->mQuickPayButton[i]->setVisible(FALSE); + } + } + + // build a string containing the maximum value and calc nerw button width from it. + std::string balance_str = "L$"; + balance_str += LLResMgr::getInstance()->getMonetaryString( max_pay_amount ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); + S32 new_button_width = font->getWidth( std::string(balance_str)); + new_button_width += ( 12 + 12 ); // padding + + // dialong is sized for 2 digit pay amounts - larger pay values need to be scaled + const S32 threshold = 100000; + if ( max_pay_amount >= threshold ) + { + S32 num_digits_threshold = (S32)log10((double)threshold) + 1; + S32 num_digits_max = (S32)log10((double)max_pay_amount) + 1; + + // calculate the extra width required by 2 buttons with max amount and some commas + padding_required = ( num_digits_max - num_digits_threshold + ( num_digits_max / 3 ) ) * font->getWidth( std::string("0") ); + }; + + // change in button width + S32 button_delta = new_button_width - FASTPAY_BUTTON_WIDTH; + if ( button_delta < 0 ) + button_delta = 0; + + // now we know the maximum amount, we can resize all the buttons to be + for (i=0;i<num_blocks;++i) + { + LLRect r; + r = self->mQuickPayButton[i]->getRect(); + + // RHS button colum needs to move further because LHS changed too + if ( i % 2 ) + { + r.setCenterAndSize( r.getCenterX() + ( button_delta * 3 ) / 2 , + r.getCenterY(), + r.getWidth() + button_delta, + r.getHeight() ); + } + else + { + r.setCenterAndSize( r.getCenterX() + button_delta / 2, + r.getCenterY(), + r.getWidth() + button_delta, + r.getHeight() ); + } + self->mQuickPayButton[i]->setRect( r ); + } + + for (i=num_blocks;i<MAX_PAY_BUTTONS;++i) + { + self->mQuickPayButton[i]->setVisible(FALSE); + } + + self->reshape( self->getRect().getWidth() + padding_required, self->getRect().getHeight(), FALSE ); + } + msg->setHandlerFunc("PayPriceReply",NULL,NULL); +} + +// static +void LLFloaterPay::payViaObject(money_callback callback, LLSafeHandle<LLObjectSelection> selection) +{ + // Object that lead to the selection, may be child + LLViewerObject* object = selection->getPrimaryObject(); + if (!object) + return; + + LLFloaterPay *floater = LLFloaterReg::showTypedInstance<LLFloaterPay>("pay_object", LLSD(object->getID())); + if (!floater) + return; + + floater->setCallback(callback); + // Hold onto the selection until we close + floater->mObjectSelection = selection; + + LLSelectNode* node = selection->getFirstRootNode(); + if (!node) + { + //FIXME: notify user object no longer exists + floater->closeFloater(); + return; + } + + LLHost target_region = object->getRegion()->getHost(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RequestPayPrice); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); + msg->sendReliable(target_region); + msg->setHandlerFuncFast(_PREHASH_PayPriceReply, processPayPriceReply,(void **)floater); + + LLUUID owner_id; + BOOL is_group = FALSE; + node->mPermissions->getOwnership(owner_id, is_group); + + floater->childSetText("object_name_text",node->mName); + + floater->finishPayUI(owner_id, is_group); +} + +void LLFloaterPay::payDirectly(money_callback callback, + const LLUUID& target_id, + bool is_group) +{ + LLFloaterPay *floater = LLFloaterReg::showTypedInstance<LLFloaterPay>("pay_resident", LLSD(target_id)); + if (!floater) + return; + + floater->setCallback(callback); + floater->mObjectSelection = NULL; + + floater->childSetVisible("amount", TRUE); + floater->childSetVisible("pay btn", TRUE); + floater->childSetVisible("amount text", TRUE); + + floater->childSetVisible("fastpay text",TRUE); + for(S32 i=0;i<MAX_PAY_BUTTONS;++i) + { + floater->mQuickPayButton[i]->setVisible(TRUE); + } + + floater->finishPayUI(target_id, is_group); +} + +void LLFloaterPay::finishPayUI(const LLUUID& target_id, BOOL is_group) +{ + gCacheName->get(target_id, is_group, boost::bind(&LLFloaterPay::onCacheOwnerName, this, _1, _2, _3, _4)); + + // Make sure the amount field has focus + + childSetFocus("amount", TRUE); + + LLLineEditor* amount = getChild<LLLineEditor>("amount"); + amount->selectAll(); + mTargetIsGroup = is_group; +} + +void LLFloaterPay::onCacheOwnerName(const LLUUID& owner_id, + const std::string& firstname, + const std::string& lastname, + BOOL is_group) +{ + if (is_group) + { + childSetVisible("payee_group",true); + childSetVisible("payee_resident",false); + } + else + { + childSetVisible("payee_group",false); + childSetVisible("payee_resident",true); + } + + childSetTextArg("payee_name", "[FIRST]", firstname); + childSetTextArg("payee_name", "[LAST]", lastname); +} + +// static +void LLFloaterPay::onCancel(void* data) +{ + LLFloaterPay* self = reinterpret_cast<LLFloaterPay*>(data); + if(self) + { + self->closeFloater(); + } +} + +// static +void LLFloaterPay::onKeystroke(LLLineEditor*, void* data) +{ + LLFloaterPay* self = reinterpret_cast<LLFloaterPay*>(data); + if(self) + { + // enable the Pay button when amount is non-empty and positive, disable otherwise + std::string amtstr = self->childGetText("amount"); + self->childSetEnabled("pay btn", !amtstr.empty() && atoi(amtstr.c_str()) > 0); + } +} + +// static +void LLFloaterPay::onGive(void* data) +{ + LLGiveMoneyInfo* info = reinterpret_cast<LLGiveMoneyInfo*>(data); + if(info && info->mFloater) + { + info->mFloater->give(info->mAmount); + info->mFloater->closeFloater(); + } +} + +void LLFloaterPay::give(S32 amount) +{ + if(mCallback) + { + // if the amount is 0, that menas that we should use the + // text field. + if(amount == 0) + { + amount = atoi(childGetText("amount").c_str()); + } + sLastAmount = amount; + + // Try to pay an object. + if (mObjectSelection.notNull()) + { + LLViewerObject* dest_object = gObjectList.findObject(mTargetUUID); + if(dest_object) + { + LLViewerRegion* region = dest_object->getRegion(); + if (region) + { + // Find the name of the root object + LLSelectNode* node = mObjectSelection->getFirstRootNode(); + std::string object_name; + if (node) + { + object_name = node->mName; + } + S32 tx_type = TRANS_PAY_OBJECT; + if(dest_object->isAvatar()) tx_type = TRANS_GIFT; + mCallback(mTargetUUID, region, amount, FALSE, tx_type, object_name); + mObjectSelection = NULL; + + // request the object owner in order to check if the owner needs to be unmuted + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_RequestFlags, OBJECT_PAY_REQUEST ); + msg->addUUIDFast(_PREHASH_ObjectID, mTargetUUID); + msg->sendReliable( region->getHost() ); + } + } + } + else + { + // just transfer the L$ + mCallback(mTargetUUID, gAgent.getRegion(), amount, mTargetIsGroup, TRANS_GIFT, LLStringUtil::null); + + // check if the payee needs to be unmuted + LLMuteList::getInstance()->autoRemove(mTargetUUID, LLMuteList::AR_MONEY); + } + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Namespace LLFloaterPayUtil +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void LLFloaterPayUtil::registerFloater() +{ + // Sneaky, use same code but different XML for dialogs + LLFloaterReg::add("pay_resident", "floater_pay.xml", + &LLFloaterReg::build<LLFloaterPay>); + LLFloaterReg::add("pay_object", "floater_pay_object.xml", + &LLFloaterReg::build<LLFloaterPay>); +} + +void LLFloaterPayUtil::payViaObject(money_callback callback, + LLSafeHandle<LLObjectSelection> selection) +{ + LLFloaterPay::payViaObject(callback, selection); +} + +void LLFloaterPayUtil::payDirectly(money_callback callback, + const LLUUID& target_id, + bool is_group) +{ + LLFloaterPay::payDirectly(callback, target_id, is_group); +} diff --git a/indra/newview/llfloaterpay.h b/indra/newview/llfloaterpay.h new file mode 100644 index 0000000000..161ed78acb --- /dev/null +++ b/indra/newview/llfloaterpay.h @@ -0,0 +1,61 @@ +/** + * @file llfloaterpay.h + * + * $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 LLFLOATERPAY_H +#define LLFLOATERPAY_H + +#include "llsafehandle.h" + +class LLObjectSelection; +class LLUUID; +class LLViewerRegion; + +typedef void (*money_callback)(const LLUUID&, LLViewerRegion*,S32,BOOL,S32,const std::string&); + +namespace LLFloaterPayUtil +{ + /// Register with LLFloaterReg + void registerFloater(); + + /// Pay into an in-world object, which will trigger scripts and eventually + /// transfer the L$ to the resident or group that owns the object. + /// Objects must be selected. Recipient (primary) object may be a child. + void payViaObject(money_callback callback, + LLSafeHandle<LLObjectSelection> selection); + + /// Pay an avatar or group directly, not via an object in the world. + /// Scripts are not notified, L$ can be direcly transferred. + void payDirectly(money_callback callback, + const LLUUID& target_id, + bool is_group); +} + +#endif // LLFLOATERPAY_H diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 57c043a1e0..dbee9ea309 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -357,8 +357,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) BOOL LLFloaterPreference::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterPreference::onClose, this)); - LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) tabcontainer->selectFirstTab(); @@ -566,7 +564,8 @@ void LLFloaterPreference::setHardwareDefaults() refreshEnabledGraphics(); } -void LLFloaterPreference::onClose() +//virtual +void LLFloaterPreference::onClose(bool app_quitting) { gSavedSettings.setS32("LastPrefTab", getChild<LLTabContainer>("pref core")->getCurrentPanelIndex()); LLPanelLogin::setAlwaysRefresh(false); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index ce31abcd9e..34723b8c7e 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -70,8 +70,9 @@ public: void apply(); void cancel(); /*virtual*/ void draw(); - virtual BOOL postBuild(); - virtual void onOpen(const LLSD& key); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_quitting); // static data update, called from message handler static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email); @@ -79,10 +80,7 @@ public: // refresh all the graphics preferences menus static void refreshEnabledGraphics(); -protected: - - void onClose(); - +protected: void onBtnOK(); void onBtnCancel(); void onBtnApply(); diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 9e203c4269..43d31aa30a 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -58,7 +58,7 @@ class LLFloaterSellLandUI public: LLFloaterSellLandUI(const LLSD& key); virtual ~LLFloaterSellLandUI(); - void onClose(); + /*virtual*/ void onClose(bool app_quitting); private: class SelectionObserver : public LLParcelObserver @@ -131,7 +131,6 @@ LLFloaterSellLandUI::LLFloaterSellLandUI(const LLSD& key) mRegion(0) { LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver); - mCloseSignal.connect(boost::bind(&LLFloaterSellLandUI::onClose, this)); } LLFloaterSellLandUI::~LLFloaterSellLandUI() @@ -140,7 +139,7 @@ LLFloaterSellLandUI::~LLFloaterSellLandUI() } // Because we are single_instance, we are not destroyed on close. -void LLFloaterSellLandUI::onClose() +void LLFloaterSellLandUI::onClose(bool app_quitting) { // Must release parcel selection to allow land to deselect, see EXT-803 mParcelSelection = NULL; diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index c08996cc26..320647ff1a 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -77,12 +77,14 @@ #include "lltoolpipette.h" #include "lltoolplacer.h" #include "lltoolselectland.h" +#include "lltrans.h" #include "llui.h" +#include "llviewercontrol.h" +#include "llviewerjoystick.h" +#include "llviewerregion.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" #include "llviewerwindow.h" -#include "llviewercontrol.h" -#include "llviewerjoystick.h" #include "lluictrlfactory.h" // Globals @@ -198,9 +200,7 @@ LLPCode toolData[]={ LL_PCODE_LEGACY_GRASS}; BOOL LLFloaterTools::postBuild() -{ - mCloseSignal.connect(boost::bind(&LLFloaterTools::onClose, this)); - +{ // Hide until tool selected setVisible(FALSE); @@ -724,7 +724,8 @@ void LLFloaterTools::onOpen(const LLSD& key) //gMenuBarView->setItemVisible("BuildTools", TRUE); } -void LLFloaterTools::onClose() +// virtual +void LLFloaterTools::onClose(bool app_quitting) { mTab->setVisible(FALSE); @@ -980,27 +981,86 @@ void LLFloaterTools::onFocusReceived() void LLFloaterTools::refreshMedia() { getMediaState(); - LLFloaterMediaSettings::getInstance(); - LLFloaterMediaSettings::initValues(mMediaSettings ); } - +bool LLFloaterTools::selectedMediaEditable() +{ + U32 owner_mask_on; + U32 owner_mask_off; + U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_OWNER, + &owner_mask_on, &owner_mask_off ); + U32 group_mask_on; + U32 group_mask_off; + U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_GROUP, + &group_mask_on, &group_mask_off ); + U32 everyone_mask_on; + U32 everyone_mask_off; + S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_EVERYONE, + &everyone_mask_on, &everyone_mask_off ); + + bool selected_Media_editable = false; + + // if perms we got back are valid + if ( valid_owner_perms && + valid_group_perms && + valid_everyone_perms ) + { + + if ( ( owner_mask_on & PERM_MODIFY ) || + ( group_mask_on & PERM_MODIFY ) || + ( group_mask_on & PERM_MODIFY ) ) + { + selected_Media_editable = true; + } + else + // user is NOT allowed to press the RESET button + { + selected_Media_editable = false; + }; + }; + + return selected_Media_editable; +} void LLFloaterTools::getMediaState() { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* first_object = selected_objects->getFirstObject(); + LLLineEditor* media_info = getChild<LLLineEditor>("media_info"); + + if( !(first_object + && first_object->getPCode() == LL_PCODE_VOLUME + &&first_object->permModify() + )) + { + childSetEnabled("media_tex", FALSE); + childSetEnabled("add_media", FALSE); + childSetEnabled("delete_media", FALSE); + childSetEnabled("edit_media", FALSE); + childSetEnabled("media_info", FALSE); + media_info->setEnabled(FALSE); + media_info->clear(); + clearMediaSettings(); + return; + } - if( !objectp ) + std::string url = first_object->getRegion()->getCapability("ObjectMedia"); + bool has_media_capability = (!url.empty()); + + if(!has_media_capability) { childSetEnabled("media_tex", FALSE); childSetEnabled("add_media", FALSE); childSetEnabled("delete_media", FALSE); childSetEnabled("edit_media", FALSE); - updateMediaSettings(); + childSetEnabled("media_info", FALSE); + media_info->setEnabled(FALSE); + media_info->clear(); + clearMediaSettings(); return; } - bool editable = gAgent.isGodlike() || (objectp->permModify() && objectp->getPCode() == LL_PCODE_VOLUME); + bool editable = (first_object->permModify());// && selectedMediaEditable()); // Media settings U8 has_media = (U8)0; @@ -1011,24 +1071,104 @@ void LLFloaterTools::getMediaState() return (object->getTE(face)->getMediaTexGen()); } } func; - bool identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, has_media ); + // check if all faces have media(or, all dont have media) + LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue( &func, has_media ); + bool bool_has_media = (has_media & LLTextureEntry::MF_HAS_MEDIA); + + const LLMediaEntry default_media_data; + + struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry> + { + functor_getter_media_data(const LLMediaEntry& entry): mMediaEntry(entry) {} + + LLMediaEntry get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return *(object->getTE(face)->getMediaData()); + return mMediaEntry; + }; + + const LLMediaEntry& mMediaEntry; + + } func_media_data(default_media_data); + + LLMediaEntry media_data_get; + LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue( &func_media_data, media_data_get )); + + std::string multi_media_info_str = LLTrans::getString("Multiple Media"); + std::string media_title = ""; // update UI depending on whether "object" (prim or face) has media // and whether or not you are allowed to edit it. - bool bool_has_media = (has_media & LLTextureEntry::MF_HAS_MEDIA); - childSetEnabled("media_tex", bool_has_media & editable); - childSetEnabled( "edit_media", bool_has_media & editable ); - childSetEnabled( "delete_media", bool_has_media & editable ); - childSetEnabled( "add_media", ( ! bool_has_media ) & editable ); + + // IF all the faces have media (or all dont have media) + if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) + { + // TODO: get media title and set it. + media_info->clear(); + // if identical is set, all faces are same (whether all empty or has the same media) + if(!(LLFloaterMediaSettings::getInstance()->mMultipleMedia) ) + { + // Media data is valid + if(media_data_get!=default_media_data) + { + //TODO: get Meida title + //media_title = media_data_get->getTile(); + //LLFloaterMediaSettings::getInstance()->mIdenticalValidMedia = true; + media_title = media_data_get.getHomeURL(); + } + // else all faces might be empty. + + + } + else // there' re Different Medias' been set on on the faces. + { + media_title = multi_media_info_str; + } + + childSetEnabled("media_tex", bool_has_media & editable); + childSetEnabled( "edit_media", bool_has_media & editable ); + childSetEnabled( "delete_media", bool_has_media & editable ); + childSetEnabled( "add_media", ( ! bool_has_media ) & editable ); + media_info->setEnabled(bool_has_media & editable); + // TODO: display a list of all media on the face - use 'identical' flag + } + else // not all face has media but at least one does. + { + // seleted faces have not identical value + LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data ); + + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + media_title = multi_media_info_str; + } + else + { + // Media data is valid + if(media_data_get!=default_media_data) + { + //TODO: get Meida title + //media_title = media_data_get->getTile(); + media_title = media_data_get.getHomeURL(); + } + + } + + media_info->setEnabled(TRUE); + media_info->setTentative(true); + childSetEnabled("media_tex", TRUE); + childSetEnabled( "edit_media", TRUE); + childSetEnabled( "delete_media", TRUE); + childSetEnabled( "add_media", FALSE ); + } + media_info->setText(media_title); // load values for media settings updateMediaSettings(); - // if identical is set, all faces are same - if ( identical ) - { - // TODO: display a list of all media on the face - use 'identical' flag - }; + LLFloaterMediaSettings::initValues(mMediaSettings, editable ); } @@ -1104,6 +1244,12 @@ bool LLFloaterTools::deleteMediaConfirm(const LLSD& notification, const LLSD& re return false; } +void LLFloaterTools::clearMediaSettings() +{ + LLFloaterMediaSettings::getInstance(); + LLFloaterMediaSettings::clearValues(false); + +} ////////////////////////////////////////////////////////////////////////////// // void LLFloaterTools::updateMediaSettings() @@ -1116,23 +1262,26 @@ void LLFloaterTools::updateMediaSettings() LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); // TODO: (CP) refactor this using something clever or boost or both !! - LLMediaEntry default_media_data; + const LLMediaEntry default_media_data; // controls U8 value_u8 = default_media_data.getControls(); struct functor_getter_controls : public LLSelectedTEGetFunctor< U8 > { + functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {} + U8 get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getControls(); - LLMediaEntry default_media_data; - return default_media_data.getControls(); + return mMediaEntry.getControls(); }; - } func_controls; + const LLMediaEntry & mMediaEntry; + + } func_controls(default_media_data); identical = selected_objects->getSelectedTEValue( &func_controls, value_u8 ); base_key = std::string( LLMediaEntry::CONTROLS_KEY ); mMediaSettings[ base_key ] = value_u8; @@ -1142,17 +1291,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = default_media_data.getFirstClickInteract(); struct functor_getter_first_click : public LLSelectedTEGetFunctor< bool > { + functor_getter_first_click(const LLMediaEntry& entry): mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getFirstClickInteract(); - LLMediaEntry default_media_data; - return default_media_data.getFirstClickInteract(); + return mMediaEntry.getFirstClickInteract(); }; - } func_first_click; + const LLMediaEntry & mMediaEntry; + + } func_first_click(default_media_data); identical = selected_objects->getSelectedTEValue( &func_first_click, value_bool ); base_key = std::string( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1162,38 +1314,43 @@ void LLFloaterTools::updateMediaSettings() value_str = default_media_data.getHomeURL(); struct functor_getter_home_url : public LLSelectedTEGetFunctor< std::string > { + functor_getter_home_url(const LLMediaEntry& entry): mMediaEntry(entry) {} + std::string get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getHomeURL(); - LLMediaEntry default_media_data; - return default_media_data.getHomeURL(); + return mMediaEntry.getHomeURL(); }; - } func_home_url; + const LLMediaEntry & mMediaEntry; + + } func_home_url(default_media_data); identical = selected_objects->getSelectedTEValue( &func_home_url, value_str ); base_key = std::string( LLMediaEntry::HOME_URL_KEY ); mMediaSettings[ base_key ] = value_str; mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; - llwarns<<"Angela debug : home url string == "<<value_str<<llendl; // Current URL value_str = default_media_data.getCurrentURL(); struct functor_getter_current_url : public LLSelectedTEGetFunctor< std::string > { - std::string get( LLViewerObject* object, S32 face ) + functor_getter_current_url(const LLMediaEntry& entry): mMediaEntry(entry) {} + + std::string get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getCurrentURL(); - LLMediaEntry default_media_data; - return default_media_data.getCurrentURL(); + return mMediaEntry.getCurrentURL(); }; - } func_current_url; + const LLMediaEntry & mMediaEntry; + + } func_current_url(default_media_data); identical = selected_objects->getSelectedTEValue( &func_current_url, value_str ); base_key = std::string( LLMediaEntry::CURRENT_URL_KEY ); mMediaSettings[ base_key ] = value_str; @@ -1203,17 +1360,21 @@ void LLFloaterTools::updateMediaSettings() value_bool = default_media_data.getAutoZoom(); struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor< bool > { + + functor_getter_auto_zoom(const LLMediaEntry& entry) : mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getAutoZoom(); - LLMediaEntry default_media_data; - return default_media_data.getAutoZoom(); + return mMediaEntry.getAutoZoom(); }; - } func_auto_zoom; + const LLMediaEntry & mMediaEntry; + + } func_auto_zoom(default_media_data); identical = selected_objects->getSelectedTEValue( &func_auto_zoom, value_bool ); base_key = std::string( LLMediaEntry::AUTO_ZOOM_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1223,37 +1384,44 @@ void LLFloaterTools::updateMediaSettings() value_bool = default_media_data.getAutoPlay(); struct functor_getter_auto_play : public LLSelectedTEGetFunctor< bool > { + functor_getter_auto_play(const LLMediaEntry& entry) : mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getAutoPlay(); - LLMediaEntry default_media_data; - return default_media_data.getAutoPlay(); + return mMediaEntry.getAutoPlay(); }; - } func_auto_play; + const LLMediaEntry & mMediaEntry; + + } func_auto_play(default_media_data); identical = selected_objects->getSelectedTEValue( &func_auto_play, value_bool ); base_key = std::string( LLMediaEntry::AUTO_PLAY_KEY ); mMediaSettings[ base_key ] = value_bool; mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + // Auto scale value_bool = default_media_data.getAutoScale(); struct functor_getter_auto_scale : public LLSelectedTEGetFunctor< bool > { + functor_getter_auto_scale(const LLMediaEntry& entry): mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getAutoScale(); - LLMediaEntry default_media_data; - return default_media_data.getAutoScale();; + return mMediaEntry.getAutoScale();; }; - } func_auto_scale; + const LLMediaEntry & mMediaEntry; + + } func_auto_scale(default_media_data); identical = selected_objects->getSelectedTEValue( &func_auto_scale, value_bool ); base_key = std::string( LLMediaEntry::AUTO_SCALE_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1263,17 +1431,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = default_media_data.getAutoLoop(); struct functor_getter_auto_loop : public LLSelectedTEGetFunctor< bool > { + functor_getter_auto_loop(const LLMediaEntry& entry) : mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getAutoLoop(); - LLMediaEntry default_media_data; - return default_media_data.getAutoLoop(); + return mMediaEntry.getAutoLoop(); }; - } func_auto_loop; + const LLMediaEntry & mMediaEntry; + + } func_auto_loop(default_media_data); identical = selected_objects->getSelectedTEValue( &func_auto_loop, value_bool ); base_key = std::string( LLMediaEntry::AUTO_LOOP_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1283,17 +1454,20 @@ void LLFloaterTools::updateMediaSettings() value_int = default_media_data.getWidthPixels(); struct functor_getter_width_pixels : public LLSelectedTEGetFunctor< int > { + functor_getter_width_pixels(const LLMediaEntry& entry): mMediaEntry(entry) {} + int get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getWidthPixels(); - LLMediaEntry default_media_data; - return default_media_data.getWidthPixels(); + return mMediaEntry.getWidthPixels(); }; - } func_width_pixels; + const LLMediaEntry & mMediaEntry; + + } func_width_pixels(default_media_data); identical = selected_objects->getSelectedTEValue( &func_width_pixels, value_int ); base_key = std::string( LLMediaEntry::WIDTH_PIXELS_KEY ); mMediaSettings[ base_key ] = value_int; @@ -1303,17 +1477,20 @@ void LLFloaterTools::updateMediaSettings() value_int = default_media_data.getHeightPixels(); struct functor_getter_height_pixels : public LLSelectedTEGetFunctor< int > { - int get( LLViewerObject* object, S32 face ) + functor_getter_height_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + int get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getHeightPixels(); - LLMediaEntry default_media_data; - return default_media_data.getHeightPixels(); + return mMediaEntry.getHeightPixels(); }; - } func_height_pixels; + const LLMediaEntry & mMediaEntry; + + } func_height_pixels(default_media_data); identical = selected_objects->getSelectedTEValue( &func_height_pixels, value_int ); base_key = std::string( LLMediaEntry::HEIGHT_PIXELS_KEY ); mMediaSettings[ base_key ] = value_int; @@ -1323,17 +1500,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = default_media_data.getAltImageEnable(); struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor< bool > { - bool get( LLViewerObject* object, S32 face ) + functor_getter_enable_alt_image(const LLMediaEntry& entry): mMediaEntry(entry) {} + + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getAltImageEnable(); - LLMediaEntry default_media_data; - return default_media_data.getAltImageEnable(); + return mMediaEntry.getAltImageEnable(); }; - } func_enable_alt_image; + const LLMediaEntry & mMediaEntry; + + } func_enable_alt_image(default_media_data); identical = selected_objects->getSelectedTEValue( &func_enable_alt_image, value_bool ); base_key = std::string( LLMediaEntry::ALT_IMAGE_ENABLE_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1343,17 +1523,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER ); struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor< bool > { - bool get( LLViewerObject* object, S32 face ) + functor_getter_perms_owner_interact(const LLMediaEntry& entry): mMediaEntry(entry) {} + + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER)); - LLMediaEntry default_media_data; - return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER ); + return 0 != ( mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_OWNER ); }; - } func_perms_owner_interact; + const LLMediaEntry & mMediaEntry; + + } func_perms_owner_interact(default_media_data); identical = selected_objects->getSelectedTEValue( &func_perms_owner_interact, value_bool ); base_key = std::string( LLPanelContents::PERMS_OWNER_INTERACT_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1363,17 +1546,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER ); struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor< bool > { + functor_getter_perms_owner_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER)); - LLMediaEntry default_media_data; - return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER ); + return 0 != ( mMediaEntry.getPermsControl() & LLMediaEntry::PERM_OWNER ); }; - } func_perms_owner_control; + const LLMediaEntry & mMediaEntry; + + } func_perms_owner_control(default_media_data); identical = selected_objects ->getSelectedTEValue( &func_perms_owner_control, value_bool ); base_key = std::string( LLPanelContents::PERMS_OWNER_CONTROL_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1383,17 +1569,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP ); struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor< bool > { + functor_getter_perms_group_interact(const LLMediaEntry& entry): mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP)); - LLMediaEntry default_media_data; - return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP ); + return 0 != ( mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_GROUP ); }; - } func_perms_group_interact; + const LLMediaEntry & mMediaEntry; + + } func_perms_group_interact(default_media_data); identical = selected_objects->getSelectedTEValue( &func_perms_group_interact, value_bool ); base_key = std::string( LLPanelContents::PERMS_GROUP_INTERACT_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1403,17 +1592,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP ); struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor< bool > { + functor_getter_perms_group_control(const LLMediaEntry& entry): mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP)); - LLMediaEntry default_media_data; - return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP ); + return 0 != ( mMediaEntry.getPermsControl() & LLMediaEntry::PERM_GROUP ); }; - } func_perms_group_control; + const LLMediaEntry & mMediaEntry; + + } func_perms_group_control(default_media_data); identical = selected_objects->getSelectedTEValue( &func_perms_group_control, value_bool ); base_key = std::string( LLPanelContents::PERMS_GROUP_CONTROL_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1423,17 +1615,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor< bool > { + functor_getter_perms_anyone_interact(const LLMediaEntry& entry): mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE)); - LLMediaEntry default_media_data; - return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); + return 0 != ( mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); }; - } func_perms_anyone_interact; + const LLMediaEntry & mMediaEntry; + + } func_perms_anyone_interact(default_media_data); identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func_perms_anyone_interact, value_bool ); base_key = std::string( LLPanelContents::PERMS_ANYONE_INTERACT_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1443,17 +1638,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE ); struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor< bool > { + functor_getter_perms_anyone_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE)); - LLMediaEntry default_media_data; - return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE ); + return 0 != ( mMediaEntry.getPermsControl() & LLMediaEntry::PERM_ANYONE ); }; - } func_perms_anyone_control; + const LLMediaEntry & mMediaEntry; + + } func_perms_anyone_control(default_media_data); identical = selected_objects->getSelectedTEValue( &func_perms_anyone_control, value_bool ); base_key = std::string( LLPanelContents::PERMS_ANYONE_CONTROL_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1463,17 +1661,20 @@ void LLFloaterTools::updateMediaSettings() value_bool = default_media_data.getWhiteListEnable(); struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor< bool > { + functor_getter_whitelist_enable(const LLMediaEntry& entry) : mMediaEntry(entry) {} + bool get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getWhiteListEnable(); - LLMediaEntry default_media_data; - return default_media_data.getWhiteListEnable(); + return mMediaEntry.getWhiteListEnable(); }; - } func_whitelist_enable; + const LLMediaEntry & mMediaEntry; + + } func_whitelist_enable(default_media_data); identical = selected_objects->getSelectedTEValue( &func_whitelist_enable, value_bool ); base_key = std::string( LLMediaEntry::WHITELIST_ENABLE_KEY ); mMediaSettings[ base_key ] = value_bool; @@ -1483,17 +1684,20 @@ void LLFloaterTools::updateMediaSettings() std::vector<std::string> value_vector_str = default_media_data.getWhiteList(); struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor< std::vector<std::string> > { + functor_getter_whitelist_urls(const LLMediaEntry& entry): mMediaEntry(entry) {} + std::vector<std::string> get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getWhiteList(); - LLMediaEntry default_media_data; - return default_media_data.getWhiteList(); + return mMediaEntry.getWhiteList(); }; - } func_whitelist_urls; + const LLMediaEntry & mMediaEntry; + + } func_whitelist_urls(default_media_data); identical = selected_objects->getSelectedTEValue( &func_whitelist_urls, value_vector_str ); base_key = std::string( LLMediaEntry::WHITELIST_KEY ); mMediaSettings[ base_key ].clear(); diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index 008c9677ed..ffccf93943 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -74,6 +74,7 @@ public: /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ BOOL canClose(); + /*virtual*/ void onClose(bool app_quitting); /*virtual*/ void draw(); /*virtual*/ void onFocusReceived(); @@ -105,10 +106,10 @@ public: void onClickBtnDeleteMedia(); void onClickBtnAddMedia(); void onClickBtnEditMedia(); - + void clearMediaSettings(); + bool selectedMediaEditable(); private: - void onClose(); void refresh(); void refreshMedia(); void getMediaState(); diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 266252efea..98ca33c9cc 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -283,8 +283,6 @@ LLFloaterUIPreview::~LLFloaterUIPreview() // Perform post-build setup (defined in superclass) BOOL LLFloaterUIPreview::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterUIPreview::onClose, this, _2)); - LLPanel* main_panel_tmp = getChild<LLPanel>("main_panel"); // get a pointer to the main panel in order to... mFileList = main_panel_tmp->getChild<LLScrollListCtrl>("name_list"); // save pointer to file list // Double-click opens the floater, for convenience @@ -442,9 +440,9 @@ void LLFloaterUIPreview::onClickExportSchema() // Close click handler -- delete my displayed floater if it exists -void LLFloaterUIPreview::onClose(const LLSD& app_quitting) +void LLFloaterUIPreview::onClose(bool app_quitting) { - if(!app_quitting.asBoolean() && mDisplayedFloater) + if(!app_quitting && mDisplayedFloater) { onClickCloseDisplayedFloater(PRIMARY_FLOATER); onClickCloseDisplayedFloater(SECONDARY_FLOATER); diff --git a/indra/newview/llfloateruipreview.h b/indra/newview/llfloateruipreview.h index b8c378e2e9..2a98c90727 100644 --- a/indra/newview/llfloateruipreview.h +++ b/indra/newview/llfloateruipreview.h @@ -96,7 +96,9 @@ public: std::string getLocStr(S32 ID); // fetches the localization string based on what is selected in the drop-down menu void displayFloater(BOOL click, S32 ID, bool save = false); // needs to be public so live file can call it when it finds an update - BOOL postBuild(); // post-build setup (called by superclass' constructor) + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + void refreshList(); // refresh list (empty it out and fill it up from scratch) void addFloaterEntry(const std::string& path); // add a single file's entry to the list of floaters @@ -116,9 +118,6 @@ public: typedef std::map<std::string, std::pair<StringListPtr,StringListPtr> > DiffMap; DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors -protected: - void onClose(const LLSD& app_quitting); - private: // XUI elements for this floater LLScrollListCtrl* mFileList; // scroll list control for file list diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index a7658d90e9..b64257b11d 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -293,11 +293,11 @@ LLFloaterVoiceDeviceSettings::LLFloaterVoiceDeviceSettings(const LLSD& seed) } BOOL LLFloaterVoiceDeviceSettings::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterVoiceDeviceSettings::onClose, this)); - center(); return TRUE; } + +// virtual void LLFloaterVoiceDeviceSettings::onOpen(const LLSD& key) { if(mDevicePanel) @@ -306,7 +306,8 @@ void LLFloaterVoiceDeviceSettings::onOpen(const LLSD& key) } } -void LLFloaterVoiceDeviceSettings::onClose() +// virtual +void LLFloaterVoiceDeviceSettings::onClose(bool app_settings) { if(mDevicePanel) { diff --git a/indra/newview/llfloatervoicedevicesettings.h b/indra/newview/llfloatervoicedevicesettings.h index 2565bfad2b..f1603dc414 100644 --- a/indra/newview/llfloatervoicedevicesettings.h +++ b/indra/newview/llfloatervoicedevicesettings.h @@ -68,8 +68,9 @@ class LLFloaterVoiceDeviceSettings : public LLFloater public: - virtual BOOL postBuild(); + /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_settings); /*virtual*/ void draw(); void apply(); void cancel(); @@ -78,9 +79,7 @@ private: protected: static void* createPanelVoiceDeviceSettings(void* user_data); - - void onClose(); - + protected: LLPanelVoiceDeviceSettings* mDevicePanel; }; diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 098a5197df..d653d44f8c 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -183,8 +183,6 @@ void* LLFloaterWorldMap::createWorldMapView(void* data) BOOL LLFloaterWorldMap::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterWorldMap::onClose, this)); - mTabs = getChild<LLTabContainer>("maptab"); if (!mTabs) return FALSE; @@ -255,7 +253,8 @@ LLFloaterWorldMap* LLFloaterWorldMap::getInstance() return LLFloaterReg::getTypedInstance<LLFloaterWorldMap>("world_map"); } -void LLFloaterWorldMap::onClose() +// virtual +void LLFloaterWorldMap::onClose(bool app_quitting) { // While we're not visible, discard the overlay images we're using LLWorldMap::getInstance()->clearImageRefs(); diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index f117ea05af..6d5b7543d4 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -65,6 +65,7 @@ public: BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_quitting); static void reloadIcons(void*); @@ -111,9 +112,7 @@ public: // teleport to the tracked item, if there is one void teleport(); -protected: - void onClose(); - +protected: void onGoHome(); void onLandmarkComboPrearrange(); diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index dde36ac25b..3e449e2c82 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -78,12 +78,11 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) } } - mCloseSignal.connect(boost::bind(&LLIMFloater::onClose, this)); - LLTransientFloaterMgr::getInstance()->registerTransientFloater(this); } -void LLIMFloater::onClose() +// virtual +void LLIMFloater::onClose(bool app_quitting) { LLIMModel::instance().sendLeaveSession(mSessionID, mOtherParticipantUUID); diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index a183212f04..f85a941be3 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -56,6 +56,7 @@ public: /*virtual*/ void setVisible(BOOL visible); // LLFloater overrides + /*virtual*/ void onClose(bool app_quitting); /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); // override LLFloater's minimization according to EXT-1216 /*virtual*/ void setMinimized(BOOL minimize); @@ -79,10 +80,6 @@ public: // called when docked floater's position has been set by chiclet void setPositioned(bool b) { mPositioned = b; }; - // handler for a CLOSE signal - void onClose(); - - private: static void onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata ); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 89a885090c..4435bba0ed 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -1052,8 +1052,6 @@ LLFloaterIMPanel::~LLFloaterIMPanel() BOOL LLFloaterIMPanel::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterIMPanel::onClose, this)); - mVisibleSignal.connect(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2)); mInputEditor = getChild<LLLineEditor>("chat_editor"); @@ -1610,7 +1608,8 @@ void LLFloaterIMPanel::onInputEditorKeystroke(LLLineEditor* caller, void* userda } } -void LLFloaterIMPanel::onClose() +// virtual +void LLFloaterIMPanel::onClose(bool app_quitting) { setTyping(FALSE); diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index fb9b28ad16..57379b2c0d 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -198,7 +198,7 @@ public: // Check typing timeout timer. /*virtual*/ void draw(); - void onClose(); + /*virtual*/ void onClose(bool app_quitting); void onVisibilityChange(const LLSD& new_visibility); // add target ids to the session. diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 9b75c15597..4046c893c1 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -51,6 +51,7 @@ #include "llcontrol.h" // LLCachedControl #include "llfloater.h" #include "llfloaterreg.h" +#include "llmenubutton.h" #include "lltooltip.h" // positionViewNearMouse() #include "lluictrl.h" @@ -80,6 +81,9 @@ public: // Because floater is single instance, need to re-parse data on each spawn // (for example, inspector about same avatar but in different position) /*virtual*/ void onOpen(const LLSD& avatar_id); + + // When closing they should close their gear menu + /*virtual*/ void onClose(bool app_quitting); // Inspectors close themselves when they lose focus /*virtual*/ void onFocusLost(); @@ -288,6 +292,12 @@ void LLInspectAvatar::onOpen(const LLSD& data) updateVolumeSlider(); } +// virtual +void LLInspectAvatar::onClose(bool app_quitting) +{ + getChild<LLMenuButton>("gear_btn")->hideMenu(); +} + //virtual void LLInspectAvatar::onFocusLost() { diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index b0e6273c41..8c38e785e9 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -46,6 +46,7 @@ #include "llcontrol.h" // LLCachedControl #include "llfloater.h" #include "llfloaterreg.h" +#include "llmenubutton.h" #include "llresmgr.h" // getMonetaryString #include "llsafehandle.h" #include "lltextbox.h" // for description truncation @@ -81,7 +82,7 @@ public: /*virtual*/ void onOpen(const LLSD& avatar_id); // Release the selection and do other cleanup - void onClose(); + /*virtual*/ void onClose(bool app_quitting); // Inspectors close themselves when they lose focus /*virtual*/ void onFocusLost(); @@ -175,8 +176,6 @@ BOOL LLInspectObject::postBuild(void) LLSelectMgr::getInstance()->mUpdateSignal.connect( boost::bind(&LLInspectObject::update, this) ); - mCloseSignal.connect( boost::bind(&LLInspectObject::onClose, this) ); - return TRUE; } @@ -250,10 +249,13 @@ void LLInspectObject::onOpen(const LLSD& data) } } -void LLInspectObject::onClose() +// virtual +void LLInspectObject::onClose(bool app_quitting) { // Release selection to deselect mObjectSelection = NULL; + + getChild<LLMenuButton>("gear_btn")->hideMenu(); } //virtual diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b996c15a7d..26ff219437 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -68,7 +68,9 @@ LLMediaCtrl::Params::Params() texture_width("texture_width", 1024), texture_height("texture_height", 1024), caret_color("caret_color") -{} +{ + tab_stop(false); +} LLMediaCtrl::LLMediaCtrl( const Params& p) : LLPanel( p ), @@ -903,6 +905,12 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; }; break; + + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; + }; + break; }; // chain all events to any potential observers of this object. diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp new file mode 100644 index 0000000000..e69c85f245 --- /dev/null +++ b/indra/newview/llmediadataclient.cpp @@ -0,0 +1,624 @@ +/** + * @file llmediadataclient.cpp + * @brief class for queueing up requests for media data + * + * $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 "llmediadataclient.h" + +#include <boost/lexical_cast.hpp> + +#include "llhttpstatuscodes.h" +#include "llsdutil.h" +#include "llmediaentry.h" +#include "lltextureentry.h" +#include "llviewerregion.h" + +// +// When making a request +// - obtain the "overall interest score" of the object. +// This would be the sum of the impls' interest scores. +// - put the request onto a queue sorted by this score +// (highest score at the front of the queue) +// - On a timer, once a second, pull off the head of the queue and send +// the request. +// - Any request that gets a 503 still goes through the retry logic +// + +const F32 LLMediaDataClient::QUEUE_TIMER_DELAY = 1.0; // seconds(s) +const F32 LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY = 5.0; // secs +const U32 LLMediaDataClient::MAX_RETRIES = 4; + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Request +// +////////////////////////////////////////////////////////////////////////////////////// +/*static*/U32 LLMediaDataClient::Request::sNum = 0; + +LLMediaDataClient::Request::Request(const std::string &cap_name, + const LLSD& sd_payload, + LLMediaDataClientObject *obj, + LLMediaDataClient *mdc) + : mCapName(cap_name), + mPayload(sd_payload), + mObject(obj), + mNum(++sNum), + mRetryCount(0), + mMDC(mdc) +{ +} + +LLMediaDataClient::Request::~Request() +{ + LL_DEBUGS("LLMediaDataClient") << "~Request" << (*this) << LL_ENDL; + mMDC = NULL; + mObject = NULL; +} + + +std::string LLMediaDataClient::Request::getCapability() const +{ + return getObject()->getCapabilityUrl(getCapName()); +} + +// Helper function to get the "type" of request, which just pokes around to +// discover it. +LLMediaDataClient::Request::Type LLMediaDataClient::Request::getType() const +{ + if (mCapName == "ObjectMediaNavigate") + { + return NAVIGATE; + } + else if (mCapName == "ObjectMedia") + { + const std::string &verb = mPayload["verb"]; + if (verb == "GET") + { + return GET; + } + else if (verb == "UPDATE") + { + return UPDATE; + } + } + llassert(false); + return GET; +} + +const char *LLMediaDataClient::Request::getTypeAsString() const +{ + Type t = getType(); + switch (t) + { + case GET: + return "GET"; + break; + case UPDATE: + return "UPDATE"; + break; + case NAVIGATE: + return "NAVIGATE"; + break; + } + return ""; +} + + +void LLMediaDataClient::Request::reEnqueue() const +{ + // I sure hope this doesn't deref a bad pointer: + mMDC->enqueue(this); +} + +F32 LLMediaDataClient::Request::getRetryTimerDelay() const +{ + return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY : + mMDC->mRetryTimerDelay; +} + +U32 LLMediaDataClient::Request::getMaxNumRetries() const +{ + return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries; +} + +std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) +{ + s << "<request>" + << "<num>" << r.getNum() << "</num>" + << "<type>" << r.getTypeAsString() << "</type>" + << "<object_id>" << r.getObject()->getID() << "</object_id>" + << "<num_retries>" << r.getRetryCount() << "</num_retries>" + << "</request> "; + return s; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Responder::RetryTimer +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr) + : LLEventTimer(time), mResponder(mdr) +{ +} + +// virtual +LLMediaDataClient::Responder::RetryTimer::~RetryTimer() +{ + LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL; + mResponder = NULL; +} + +// virtual +BOOL LLMediaDataClient::Responder::RetryTimer::tick() +{ + // Instead of retrying, we just put the request back onto the queue + LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << "retrying" << LL_ENDL; + mResponder->getRequest()->reEnqueue(); + // Don't fire again + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Responder +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::Responder::Responder(const request_ptr_t &request) + : mRequest(request) +{ +} + +LLMediaDataClient::Responder::~Responder() +{ + LL_DEBUGS("LLMediaDataClient") << "~Responder" << *(getRequest()) << LL_ENDL; + mRequest = NULL; +} + +/*virtual*/ +void LLMediaDataClient::Responder::error(U32 status, const std::string& reason) +{ + if (status == HTTP_SERVICE_UNAVAILABLE) + { + F32 retry_timeout = mRequest->getRetryTimerDelay(); + + mRequest->incRetryCount(); + + if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) + { + LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; + + // Start timer (instances are automagically tracked by + // InstanceTracker<> and LLEventTimer) + new RetryTimer(F32(retry_timeout/*secs*/), this); + } + else { + LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retry count " << + mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; + } + } + else { + std::string msg = boost::lexical_cast<std::string>(status) + ": " + reason; + LL_WARNS("LLMediaDataClient") << *mRequest << " http error(" << msg << ")" << LL_ENDL; + } +} + + +/*virtual*/ +void LLMediaDataClient::Responder::result(const LLSD& content) +{ + LL_INFOS("LLMediaDataClient") << *mRequest << "result : " << ll_pretty_print_sd(content) << LL_ENDL; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Comparator +// +////////////////////////////////////////////////////////////////////////////////////// + +bool LLMediaDataClient::Comparator::operator() (const request_ptr_t &o1, const request_ptr_t &o2) const +{ + if (o2.isNull()) return true; + if (o1.isNull()) return false; + + // The score is intended to be a measure of how close an object is or + // how much screen real estate (interest) it takes up + // Further away = lower score. + // Lesser interest = lower score + // For instance, here are some cases: + // 1: Two items with no impl, closest one wins + // 2: Two items with an impl: interest should rule, but distance is + // still taken into account (i.e. something really close might take + // precedence over a large item far away) + // 3: One item with an impl, another without: item with impl wins + // (XXX is that what we want?) + // Calculate the scores for each. + F64 o1_score = Comparator::getObjectScore(o1->getObject()); + F64 o2_score = Comparator::getObjectScore(o2->getObject()); + + // XXX Weird: a higher score should go earlier, but by observation I notice + // that this causes further-away objects load first. This is counterintuitive + // to the priority_queue Comparator, which states that this function should + // return 'true' if o1 should be *before* o2. + // In other words, I'd have expected that the following should return + // ( o1_score > o2_score). + return ( o1_score < o2_score ); +} + +// static +F64 LLMediaDataClient::Comparator::getObjectScore(const LLMediaDataClientObject::ptr_t &obj) +{ + // *TODO: make this less expensive? + F64 dist = obj->getDistanceFromAvatar() + 0.1; // avoids div by 0 + // square the distance so that they are in the same "unit magnitude" as + // the interest (which is an area) + dist *= dist; + F64 interest = obj->getTotalMediaInterest() + 1.0; + + return interest/dist; +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::PriorityQueue +// Queue of LLMediaDataClientObject smart pointers to request media for. +// +////////////////////////////////////////////////////////////////////////////////////// + +// dump the queue +std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::PriorityQueue &q) +{ + int i = 0; + std::vector<LLMediaDataClient::request_ptr_t>::const_iterator iter = q.c.begin(); + std::vector<LLMediaDataClient::request_ptr_t>::const_iterator end = q.c.end(); + while (iter < end) + { + s << "\t" << i << "]: " << (*iter)->getObject()->getID().asString(); + iter++; + i++; + } + return s; +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::QueueTimer +// Queue of LLMediaDataClientObject smart pointers to request media for. +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc) + : LLEventTimer(time), mMDC(mdc) +{ + mMDC->setIsRunning(true); +} + +LLMediaDataClient::QueueTimer::~QueueTimer() +{ + LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL; + mMDC->setIsRunning(false); + mMDC = NULL; +} + +// virtual +BOOL LLMediaDataClient::QueueTimer::tick() +{ + if (NULL == mMDC->pRequestQueue) + { + // Shutting down? stop. + LL_DEBUGS("LLMediaDataClient") << "queue gone" << LL_ENDL; + return TRUE; + } + + LLMediaDataClient::PriorityQueue &queue = *(mMDC->pRequestQueue); + + if (queue.empty()) + { + LL_DEBUGS("LLMediaDataClient") << "queue empty: " << queue << LL_ENDL; + return TRUE; + } + + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue is: " << queue << LL_ENDL; + + // Peel one off of the items from the queue, and execute request + request_ptr_t request = queue.top(); + llassert(!request.isNull()); + const LLMediaDataClientObject *object = request->getObject(); + bool performed_request = false; + llassert(NULL != object); + if (NULL != object && object->hasMedia()) + { + std::string url = request->getCapability(); + if (!url.empty()) + { + const LLSD &sd_payload = request->getPayload(); + LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL; + + // Call the subclass for creating the responder + LLHTTPClient::post(url, sd_payload, mMDC->createResponder(request)); + performed_request = true; + } + else { + LL_INFOS("LLMediaDataClient") << "NOT Sending request for " << *request << ": empty cap url!" << LL_ENDL; + } + } + else { + if (!object->hasMedia()) + { + LL_INFOS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL; + } + } + bool exceeded_retries = request->getRetryCount() > mMDC->mMaxNumRetries; + if (performed_request || exceeded_retries) // Try N times before giving up + { + if (exceeded_retries) + { + LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " + << mMDC->mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL; + // XXX Should we bring up a warning dialog?? + } + queue.pop(); + } + else { + request->incRetryCount(); + } + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue is now: " << (*(mMDC->pRequestQueue)) << LL_ENDL; + + return queue.empty(); +} + +void LLMediaDataClient::startQueueTimer() +{ + if (! mQueueTimerIsRunning) + { + LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL; + // LLEventTimer automagically takes care of the lifetime of this object + new QueueTimer(mQueueTimerDelay, this); + } +} + +void LLMediaDataClient::stopQueueTimer() +{ + mQueueTimerIsRunning = false; +} + +void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload) +{ + if (object.isNull() || ! object->hasMedia()) return; + + // Push the object on the priority queue + enqueue(new Request(getCapabilityName(), payload, object, this)); +} + +void LLMediaDataClient::enqueue(const Request *request) +{ + LL_INFOS("LLMediaDataClient") << "Queuing request for " << *request << LL_ENDL; + // Push the request on the priority queue + // Sadly, we have to const-cast because items put into the queue are not const + pRequestQueue->push(const_cast<LLMediaDataClient::Request*>(request)); + LL_DEBUGS("LLMediaDataClient") << "Queue:" << (*pRequestQueue) << LL_ENDL; + // Start the timer if not already running + startQueueTimer(); +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, + F32 retry_timer_delay, + U32 max_retries) + : mQueueTimerDelay(queue_timer_delay), + mRetryTimerDelay(retry_timer_delay), + mMaxNumRetries(max_retries), + mQueueTimerIsRunning(false) +{ + pRequestQueue = new PriorityQueue(); +} + +LLMediaDataClient::~LLMediaDataClient() +{ + stopQueueTimer(); + + // This should clear the queue, and hopefully call all the destructors. + LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " << + (pRequestQueue->empty() ? "<empty> " : "<not empty> ") << (*pRequestQueue) << LL_ENDL; + delete pRequestQueue; + pRequestQueue = NULL; +} + +bool LLMediaDataClient::isEmpty() const +{ + return (NULL == pRequestQueue) ? true : pRequestQueue->empty(); +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLObjectMediaDataClient +// Subclass of LLMediaDataClient for the ObjectMedia cap +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::Responder *LLObjectMediaDataClient::createResponder(const request_ptr_t &request) const +{ + return new LLObjectMediaDataClient::Responder(request); +} + +const char *LLObjectMediaDataClient::getCapabilityName() const +{ + return "ObjectMedia"; +} + +void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object) +{ + LLSD sd_payload; + sd_payload["verb"] = "GET"; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID(); + request(object, sd_payload); +} + +void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object) +{ + LLSD sd_payload; + sd_payload["verb"] = "UPDATE"; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID(); + LLSD object_media_data; + int i = 0; + int end = object->getMediaDataCount(); + for ( ; i < end ; ++i) + { + object_media_data.append(object->getMediaDataLLSD(i)); + } + sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; + + LL_INFOS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_pretty_print_sd(sd_payload) << LL_ENDL; + + request(object, sd_payload); +} + +/*virtual*/ +void LLObjectMediaDataClient::Responder::result(const LLSD& content) +{ + const LLMediaDataClient::Request::Type type = getRequest()->getType(); + llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE) + if (type == LLMediaDataClient::Request::GET) + { + LL_INFOS("LLMediaDataClient") << *(getRequest()) << "GET returned: " << ll_pretty_print_sd(content) << LL_ENDL; + + // Look for an error + if (content.has("error")) + { + const LLSD &error = content["error"]; + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << + error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + + // XXX Warn user? + } + else { + // Check the data + const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; + if (object_id != getRequest()->getObject()->getID()) + { + // NOT good, wrong object id!! + LL_WARNS("LLMediaDataClient") << *(getRequest()) << "DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; + return; + } + + // Otherwise, update with object media data + getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY]); + } + } + else if (type == LLMediaDataClient::Request::UPDATE) + { + // just do what our superclass does + LLMediaDataClient::Responder::result(content); + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLObjectMediaNavigateClient +// Subclass of LLMediaDataClient for the ObjectMediaNavigate cap +// +////////////////////////////////////////////////////////////////////////////////////// +LLMediaDataClient::Responder *LLObjectMediaNavigateClient::createResponder(const request_ptr_t &request) const +{ + return new LLObjectMediaNavigateClient::Responder(request); +} + +const char *LLObjectMediaNavigateClient::getCapabilityName() const +{ + return "ObjectMediaNavigate"; +} + +void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url) +{ + LLSD sd_payload; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID(); + sd_payload[LLMediaEntry::CURRENT_URL_KEY] = url; + sd_payload[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)texture_index; + request(object, sd_payload); +} + +/*virtual*/ +void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string& reason) +{ + // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base + // class + if (status == HTTP_SERVICE_UNAVAILABLE) + { + LLMediaDataClient::Responder::error(status, reason); + } + else { + // bounce the face back + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; + const LLSD &payload = getRequest()->getPayload(); + // bounce the face back + getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); + } +} + +/*virtual*/ +void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +{ + LL_DEBUGS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_pretty_print_sd(content) << LL_ENDL; + + if (content.has("error")) + { + const LLSD &error = content["error"]; + int error_code = error["code"]; + + if (ERROR_PERMISSION_DENIED_CODE == error_code) + { + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL; + const LLSD &payload = getRequest()->getPayload(); + // bounce the face back + getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); + } + else { + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << + error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + } + // XXX Warn user? + } + else { + // just do what our superclass does + LLMediaDataClient::Responder::result(content); + } +} diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h new file mode 100644 index 0000000000..9d0aa0981e --- /dev/null +++ b/indra/newview/llmediadataclient.h @@ -0,0 +1,309 @@ +/** + * @file llmediadataclient.h + * @brief class for queueing up requests to the media service + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-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_LLMEDIADATACLIENT_H +#define LL_LLMEDIADATACLIENT_H + +#include "llhttpclient.h" +#include <queue> +#include "llrefcount.h" +#include "llpointer.h" +#include "lltimer.h" + + +// Link seam for LLVOVolume +class LLMediaDataClientObject : public LLRefCount +{ +public: + // Get the number of media data items + virtual U8 getMediaDataCount() const = 0; + // Get the media data at index, as an LLSD + virtual LLSD getMediaDataLLSD(U8 index) const = 0; + // Get this object's UUID + virtual LLUUID getID() const = 0; + // Navigate back to previous URL + virtual void mediaNavigateBounceBack(U8 index) = 0; + // Does this object have media? + virtual bool hasMedia() const = 0; + // Update the object's media data to the given array + virtual void updateObjectMediaData(LLSD const &media_data_array) = 0; + // Return the distance from the object to the avatar + virtual F64 getDistanceFromAvatar() const = 0; + // Return the total "interest" of the media (on-screen area) + virtual F64 getTotalMediaInterest() const = 0; + // Return the given cap url + virtual std::string getCapabilityUrl(const std::string &name) const = 0; + + // smart pointer + typedef LLPointer<LLMediaDataClientObject> ptr_t; +}; + +// This object creates a priority queue for requests. +// Abstracts the Cap URL, the request, and the responder +class LLMediaDataClient : public LLRefCount +{ +public: + LOG_CLASS(LLMediaDataClient); + + const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s) + const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs + const static U32 MAX_RETRIES;// = 4; + + // Constructor + LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES); + + // Make the request + void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload); + + F32 getRetryTimerDelay() const { return mRetryTimerDelay; } + + // Returns true iff the queue is empty + bool isEmpty() const; + +protected: + // Destructor + virtual ~LLMediaDataClient(); // use unref + + // Request + class Request : public LLRefCount + { + public: + enum Type { + GET, + UPDATE, + NAVIGATE + }; + + Request(const std::string &cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc); + const std::string &getCapName() const { return mCapName; } + const LLSD &getPayload() const { return mPayload; } + LLMediaDataClientObject *getObject() const { return mObject; } + + U32 getNum() const { return mNum; } + + U32 getRetryCount() const { return mRetryCount; } + void incRetryCount() { mRetryCount++; } + + // Note: may return empty string! + std::string getCapability() const; + + Type getType() const; + const char *getTypeAsString() const; + + // Re-enqueue thyself + void reEnqueue() const; + + F32 getRetryTimerDelay() const; + U32 getMaxNumRetries() const; + + public: + friend std::ostream& operator<<(std::ostream &s, const Request &q); + + protected: + virtual ~Request(); // use unref(); + + private: + std::string mCapName; + LLSD mPayload; + LLMediaDataClientObject::ptr_t mObject; + // Simple tracking + const U32 mNum; + static U32 sNum; + U32 mRetryCount; + + // Back pointer to the MDC...not a ref! + LLMediaDataClient *mMDC; + }; + typedef LLPointer<Request> request_ptr_t; + + // Responder + class Responder : public LLHTTPClient::Responder + { + public: + Responder(const request_ptr_t &request); + //If we get back an error (not found, etc...), handle it here + virtual void error(U32 status, const std::string& reason); + //If we get back a normal response, handle it here. Default just logs it. + virtual void result(const LLSD& content); + + const request_ptr_t &getRequest() const { return mRequest; } + + protected: + virtual ~Responder(); + + private: + + class RetryTimer : public LLEventTimer + { + public: + RetryTimer(F32 time, Responder *); + virtual ~RetryTimer(); + virtual BOOL tick(); + private: + // back-pointer + boost::intrusive_ptr<Responder> mResponder; + }; + + request_ptr_t mRequest; + }; + +protected: + + void enqueue(const Request*); + + // Subclasses must override this factory method to return a new responder + virtual Responder *createResponder(const request_ptr_t &request) const = 0; + + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const = 0; + +private: + + // Comparator for PriorityQueue + class Comparator + { + public: + bool operator() (const request_ptr_t &o1, const request_ptr_t &o2) const; + private: + static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); + }; + + // PriorityQueue + class PriorityQueue : public std::priority_queue< + request_ptr_t, + std::vector<request_ptr_t>, + Comparator > + { + public: + friend std::ostream& operator<<(std::ostream &s, const PriorityQueue &q); + }; + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + friend std::ostream& operator<<(std::ostream &s, const PriorityQueue &q); + + class QueueTimer : public LLEventTimer + { + public: + QueueTimer(F32 time, LLMediaDataClient *mdc); + virtual BOOL tick(); + protected: + virtual ~QueueTimer(); + private: + // back-pointer + LLPointer<LLMediaDataClient> mMDC; + }; + + void startQueueTimer(); + void stopQueueTimer(); + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } + + const F32 mQueueTimerDelay; + const F32 mRetryTimerDelay; + const U32 mMaxNumRetries; + + bool mQueueTimerIsRunning; + + PriorityQueue *pRequestQueue; +}; + + +// MediaDataResponder specific for the ObjectMedia cap +class LLObjectMediaDataClient : public LLMediaDataClient +{ +public: + LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) + {} + ~LLObjectMediaDataClient() {} + + void fetchMedia(LLMediaDataClientObject *object); + void updateMedia(LLMediaDataClientObject *object); + +protected: + // Subclasses must override this factory method to return a new responder + virtual Responder *createResponder(const request_ptr_t &request) const; + + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; + + class Responder : public LLMediaDataClient::Responder + { + public: + Responder(const request_ptr_t &request) + : LLMediaDataClient::Responder(request) {} + virtual void result(const LLSD &content); + }; +}; + + +// MediaDataResponder specific for the ObjectMediaNavigate cap +class LLObjectMediaNavigateClient : public LLMediaDataClient +{ +public: + // NOTE: from llmediaservice.h + static const int ERROR_PERMISSION_DENIED_CODE = 8002; + + LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) + {} + ~LLObjectMediaNavigateClient() {} + + void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url); + +protected: + // Subclasses must override this factory method to return a new responder + virtual Responder *createResponder(const request_ptr_t &request) const; + + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; + + class Responder : public LLMediaDataClient::Responder + { + public: + Responder(const request_ptr_t &request) + : LLMediaDataClient::Responder(request) {} + virtual void error(U32 status, const std::string& reason); + virtual void result(const LLSD &content); + private: + void mediaNavigateBounceBack(); + }; + +}; + + +#endif // LL_LLMEDIADATACLIENT_H diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index 599e6b6859..7c8ffa3b94 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -72,11 +72,9 @@ public: void onNearbyChatContextMenuItemClicked(const LLSD& userdata); bool onNearbyChatCheckContextMenuItem(const LLSD& userdata); - virtual void onClose (bool app_quitting) { if(app_quitting) destroy(); else setVisible(false); } + /*virtual*/ void onOpen (const LLSD& key); - virtual void onOpen (const LLSD& key); - - virtual void draw (); + /*virtual*/ void draw (); private: void add_timestamped_line(const LLChat& chat, const LLColor4& color); diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 1ed5fa4357..a03902caba 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -78,11 +78,11 @@ public: * Profile tabs should close any opened panels here. * * Called from LLPanelProfile::onOpen() before opening new profile. - * See LLPanelpicks::onClose for example. LLPanelPicks closes picture info panel + * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel * before new profile is displayed, otherwise new profile will * be hidden behind picture info panel. */ - virtual void onClose() {} + virtual void onClosePanel() {} /** * Resets controls visibility, state, etc. diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index c61b987b1c..ee0426c7df 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -786,8 +786,8 @@ void LLPanelFace::getState() childSetEnabled("button align",FALSE); childSetEnabled("button apply",FALSE); - childSetEnabled("has media", FALSE); - childSetEnabled("media info set", FALSE); + //childSetEnabled("has media", FALSE); + //childSetEnabled("media info set", FALSE); } } diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index be40d6fb5f..a33d9604fe 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -49,6 +49,8 @@ #include "llpanelcontents.h" #include "llpluginclassmedia.h" #include "llfloatermediasettings.h" +#include "llfloatertools.h" +#include "lltrans.h" //////////////////////////////////////////////////////////////////////////////// // @@ -155,43 +157,11 @@ void LLPanelMediaSettingsGeneral::draw() }; // current URL can change over time. - updateCurrentURL(); +// updateCurrentURL(); // enable/disable RESRET button depending on permissions // since this is the same as a navigate action - U32 owner_mask_on; - U32 owner_mask_off; - U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_OWNER, - &owner_mask_on, &owner_mask_off ); - U32 group_mask_on; - U32 group_mask_off; - U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_GROUP, - &group_mask_on, &group_mask_off ); - U32 everyone_mask_on; - U32 everyone_mask_off; - S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_EVERYONE, - &everyone_mask_on, &everyone_mask_off ); - - bool user_can_press_reset = false; - - // if perms we got back are valid - if ( valid_owner_perms && - valid_group_perms && - valid_everyone_perms ) - { - // if user is allowed to press the RESET button - if ( ( owner_mask_on & PERM_MODIFY ) || - ( group_mask_on & PERM_MODIFY ) || - ( group_mask_on & PERM_MODIFY ) ) - { - user_can_press_reset = true; - } - else - // user is NOT allowed to press the RESET button - { - user_can_press_reset = false; - }; - }; + bool user_can_press_reset = gFloaterTools->selectedMediaEditable(); // several places modify this widget so we must collect states in one place if ( reset_button_is_active ) @@ -216,7 +186,7 @@ void LLPanelMediaSettingsGeneral::draw() //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsGeneral::clearValues( void* userdata ) +void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; self->mAltImageEnable ->clear(); @@ -230,12 +200,23 @@ void LLPanelMediaSettingsGeneral::clearValues( void* userdata ) self->mHeightPixels->clear(); self->mHomeURL->clear(); self->mWidthPixels->clear(); + self->mAltImageEnable ->setEnabled(editable); + 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->mPreviewMedia->unloadMediaSource(); } //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ) +void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ,bool editable) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; @@ -243,6 +224,29 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_ //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, editable); + // only show multiple + self->mHomeURL ->setText(LLTrans::getString("Multiple Media")); + return; + } + + } + else + { + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + self->clearValues(self, editable); + // only show multiple + self->mHomeURL ->setText(LLTrans::getString("Multiple Media")); + return; + } + + } std::string base_key( "" ); std::string tentative_key( "" ); @@ -293,10 +297,11 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_ static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )-> setValue( media_settings[ base_key ].asInteger() ); + data_set[ i ].ctrl_ptr->setEnabled(editable); data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); }; }; - + // interrogates controls and updates widgets as required self->updateMediaPreview(); self->updateCurrentURL(); @@ -322,30 +327,17 @@ void LLPanelMediaSettingsGeneral::updateMediaPreview() // Helper to set current URL void LLPanelMediaSettingsGeneral::updateCurrentURL() { - if( mPreviewMedia ) + if( mCurrentURL->getText().empty() ) { - LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); - if( media_plugin ) - { - // get current URL from plugin and display - std::string current_location = media_plugin->getLocation(); - if ( current_location.length() ) - { - childSetText( "current_url", current_location ); - } - else - // current location may be empty so we need to clear it - { - const std::string empty_string( "" ); - childSetText( "current_url", empty_string ); - }; - }; - }; + childSetText( "current_url", mHomeURL->getText() ); + } + } //////////////////////////////////////////////////////////////////////////////// -void LLPanelMediaSettingsGeneral::onClose() +// virtual +void LLPanelMediaSettingsGeneral::onClose(bool app_quitting) { if(mPreviewMedia) { @@ -374,7 +366,7 @@ void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl() void LLPanelMediaSettingsGeneral::apply( void* userdata ) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; - + self->mHomeURL->onCommit(); // build LLSD Fragment LLSD media_data_general; self->getValues(media_data_general); @@ -393,8 +385,7 @@ void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in ) 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(); - // XXX Don't send current URL! - //fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); + 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(); diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h index 24678a3a07..5acfa39181 100644 --- a/indra/newview/llpanelmediasettingsgeneral.h +++ b/indra/newview/llpanelmediasettingsgeneral.h @@ -48,7 +48,9 @@ class LLPanelMediaSettingsGeneral : public LLPanel { public: BOOL postBuild(); - virtual void draw(); + /*virtual*/ void draw(); + /*virtual*/ void onClose(bool app_quitting); + static void apply(void*); void getValues(LLSD &fill_me_in); @@ -56,14 +58,12 @@ public: ~LLPanelMediaSettingsGeneral(); void setParent( LLFloaterMediaSettings* parent ); - static void initValues( void* userdata, const LLSD& media_settings ); - static void clearValues( void* userdata ); + static void initValues( void* userdata, const LLSD& media_settings ,bool editable); + static void clearValues( void* userdata, bool editable); void updateMediaPreview(); void updateCurrentURL(); - void onClose(); - protected: LLFloaterMediaSettings* mParent; @@ -74,7 +74,7 @@ private: LLComboBox* mControls; LLCheckBoxCtrl* mAutoLoop; LLCheckBoxCtrl* mFirstClick; - LLTextureCtrl* mMediaPreview; +// LLTextureCtrl* mMediaPreview; LLCheckBoxCtrl* mAutoZoom; LLCheckBoxCtrl* mAutoPlay; LLCheckBoxCtrl* mAutoScale; diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp index d6a2677f4b..4d84874e7a 100644 --- a/indra/newview/llpanelmediasettingspermissions.cpp +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -49,7 +49,8 @@ #include "llselectmgr.h" #include "llmediaentry.h" #include "llnamebox.h" - +#include "lltrans.h" +#include "llfloatermediasettings.h" //////////////////////////////////////////////////////////////////////////////// // LLPanelMediaSettingsPermissions::LLPanelMediaSettingsPermissions() : @@ -119,7 +120,7 @@ void LLPanelMediaSettingsPermissions::draw() //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsPermissions::clearValues( void* userdata ) +void LLPanelMediaSettingsPermissions::clearValues( void* userdata, bool editable) { LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; self->mPermsOwnerInteract->clear(); @@ -128,16 +129,41 @@ void LLPanelMediaSettingsPermissions::clearValues( void* userdata ) self->mPermsGroupControl->clear(); self->mPermsWorldInteract ->clear(); self->mPermsWorldControl ->clear(); -// mPermsGroupName ->setValue(0); - + + self->mPermsOwnerInteract->setEnabled(editable); + self->mPermsOwnerControl ->setEnabled(editable); + self->mPermsGroupInteract->setEnabled(editable); + self->mPermsGroupControl ->setEnabled(editable); + self->mPermsWorldInteract->setEnabled(editable); + self->mPermsWorldControl ->setEnabled(editable); } //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& media_settings ) +void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& media_settings , bool editable) { LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) + { + if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } + else + { + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } std::string base_key( "" ); std::string tentative_key( "" ); @@ -178,10 +204,17 @@ void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& me if ( data_set[ i ].ctrl_type == "LLComboBox" ) static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> setCurrentByIndex( media_settings[ base_key ].asInteger() ); - + data_set[ i ].ctrl_ptr->setEnabled(editable); data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); }; }; + self->childSetEnabled("media_perms_label_owner", editable ); + self->childSetText("media_perms_label_owner", LLTrans::getString("Media Perms Owner") ); + self->childSetEnabled("media_perms_label_group", editable ); + self->childSetText("media_perms_label_group", LLTrans::getString("Media Perms Group") ); + self->childSetEnabled("media_perms_label_anyone", editable ); + self->childSetText("media_perms_label_anyone", LLTrans::getString("Media Perms Anyone") ); + } //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelmediasettingspermissions.h b/indra/newview/llpanelmediasettingspermissions.h index ce293e07b9..ecc50e3582 100644 --- a/indra/newview/llpanelmediasettingspermissions.h +++ b/indra/newview/llpanelmediasettingspermissions.h @@ -55,8 +55,8 @@ class LLPanelMediaSettingsPermissions : public LLPanel LLPanelMediaSettingsPermissions(); ~LLPanelMediaSettingsPermissions(); - static void initValues( void* userdata, const LLSD& media_settings ); - static void clearValues( void* userdata ); + static void initValues( void* userdata, const LLSD& media_settings, bool editable ); + static void clearValues( void* userdata, bool editable); private: LLCheckBoxCtrl* mPermsOwnerInteract; diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp index a4eee82aa9..cea105d7de 100644 --- a/indra/newview/llpanelmediasettingssecurity.cpp +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -44,7 +44,7 @@ #include "llselectmgr.h" #include "llmediaentry.h" #include "llfloaterwhitelistentry.h" - +#include "llfloatermediasettings.h" //////////////////////////////////////////////////////////////////////////////// // LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() @@ -110,10 +110,30 @@ void LLPanelMediaSettingsSecurity::draw() //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings ) +void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable) { LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) + { + if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } + else + { + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } std::string base_key( "" ); std::string tentative_key( "" ); @@ -163,7 +183,7 @@ void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media ++iter; }; }; - + data_set[ i ].ctrl_ptr->setEnabled(editable); data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); }; }; @@ -171,11 +191,13 @@ void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsSecurity::clearValues( void* userdata ) +void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable) { LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; self->mEnableWhiteList->clear(); self->mWhiteListList->deleteAllItems(); + self->mEnableWhiteList->setEnabled(editable); + self->mWhiteListList->setEnabled(editable); } //////////////////////////////////////////////////////////////////////////////// // static diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h index d77509897d..b7cf67c039 100644 --- a/indra/newview/llpanelmediasettingssecurity.h +++ b/indra/newview/llpanelmediasettingssecurity.h @@ -49,8 +49,8 @@ class LLPanelMediaSettingsSecurity : public LLPanel LLPanelMediaSettingsSecurity(); ~LLPanelMediaSettingsSecurity(); - static void initValues( void* userdata, const LLSD& media_settings ); - static void clearValues( void* userdata ); + static void initValues( void* userdata, const LLSD& media_settings,bool editable ); + static void clearValues( void* userdata, bool editable); void addWhiteListItem(const std::string& url); private: diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index e74afba25a..979e9618da 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -463,7 +463,8 @@ void LLPickItem::processProperties(void *data, EAvatarProcessorType type) LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); } -void LLPanelPicks::onClose() +// virtual +void LLPanelPicks::onClosePanel() { // Toggle off Pick Info panel if it is visible. if(mPickPanel && mPickPanel->getVisible()) diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index 7ebdc3089c..18c571c735 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -77,7 +77,7 @@ public: /** * Closes LLPanelPick if it is visible. */ - /*virtual*/ void onClose(); + /*virtual*/ void onClosePanel(); private: void onClickDelete(); diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index eb269fabe3..d6be0a9419 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -44,14 +44,16 @@ #include "llqueryflags.h" #include "llbutton.h" +#include "llcombobox.h" #include "lliconctrl.h" -#include "lllineeditor.h" #include "llscrollcontainer.h" #include "lltextbox.h" +#include "lltrans.h" #include "llaccordionctrl.h" #include "llaccordionctrltab.h" #include "llagent.h" +#include "llagentui.h" #include "llavatarpropertiesprocessor.h" #include "llfloaterworldmap.h" #include "llinventorymodel.h" @@ -64,6 +66,16 @@ #include "llviewertexteditor.h" #include "llworldmap.h" +//---------------------------------------------------------------------------- +// Aux types and methods +//---------------------------------------------------------------------------- + +typedef std::pair<LLUUID, std::string> folder_pair_t; + +static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right); +static std::string getFullFolderName(const LLViewerInventoryCategory* cat); +static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats); + static LLRegisterPanelClassWrapper<LLPanelPlaceInfo> t_place_info("panel_place_info"); LLPanelPlaceInfo::LLPanelPlaceInfo() @@ -141,11 +153,8 @@ BOOL LLPanelPlaceInfo::postBuild() mCreated = getChild<LLTextBox>("created"); mTitleEditor = getChild<LLLineEditor>("title_editor"); - mTitleEditor->setCommitCallback(boost::bind(&LLPanelPlaceInfo::onCommitTitleOrNote, this, TITLE)); - mNotesEditor = getChild<LLTextEditor>("notes_editor"); - mNotesEditor->setCommitCallback(boost::bind(&LLPanelPlaceInfo::onCommitTitleOrNote, this, NOTE)); - mNotesEditor->setCommitOnFocusLost(true); + mFolderCombo = getChild<LLComboBox>("folder_combo"); LLScrollContainer* scroll_container = getChild<LLScrollContainer>("scroll_container"); scroll_container->setBorderVisible(FALSE); @@ -316,6 +325,7 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) LLPanel* landmark_edit_panel = getChild<LLPanel>("landmark_edit_panel"); bool is_info_type_agent = type == AGENT; + bool is_info_type_create_landmark = type == CREATE_LANDMARK; bool is_info_type_landmark = type == LANDMARK; bool is_info_type_teleport_history = type == TELEPORT_HISTORY; @@ -329,7 +339,10 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) mLastVisited->setVisible(is_info_type_teleport_history); landmark_info_panel->setVisible(is_info_type_landmark); - landmark_edit_panel->setVisible(is_info_type_landmark || type == CREATE_LANDMARK); + landmark_edit_panel->setVisible(is_info_type_landmark || is_info_type_create_landmark); + + getChild<LLTextBox>("folder_lable")->setVisible(is_info_type_create_landmark); + mFolderCombo->setVisible(is_info_type_create_landmark); getChild<LLAccordionCtrl>("advanced_info_accordion")->setVisible(is_info_type_agent); @@ -337,6 +350,11 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) { case CREATE_LANDMARK: mCurrentTitle = getString("title_create_landmark"); + + mTitleEditor->setEnabled(TRUE); + mNotesEditor->setEnabled(TRUE); + + populateFoldersList(); break; case AGENT: @@ -351,6 +369,11 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) case LANDMARK: mCurrentTitle = getString("title_landmark"); + + mTitleEditor->setEnabled(FALSE); + mNotesEditor->setEnabled(FALSE); + + populateFoldersList(); break; case TELEPORT_HISTORY: @@ -485,10 +508,9 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) parcel_data.sim_name.c_str(), region_x, region_y, region_z); mRegionName->setText(name); } - + if (mInfoType == CREATE_LANDMARK) { - if (parcel_data.name.empty()) { mTitleEditor->setText(name); @@ -498,7 +520,15 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) mTitleEditor->setText(parcel_data.name); } - mNotesEditor->setText(LLStringUtil::null); + // FIXME: Creating landmark works only for current agent location. + std::string desc; + LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_FULL, gAgent.getPositionAgent()); + mNotesEditor->setText(desc); + + if (!LLLandmarkActions::landmarkAlreadyExists()) + { + createLandmark(mFolderCombo->getValue().asUUID()); + } } } @@ -694,7 +724,6 @@ void LLPanelPlaceInfo::displaySelectedParcelInfo(LLParcel* parcel, &rent_price, &for_sale, &dwell); - if (for_sale) { // Adding "For Sale" flag in remote parcel response format. @@ -803,52 +832,42 @@ void LLPanelPlaceInfo::updateLastVisitedText(const LLDate &date) } } -void LLPanelPlaceInfo::onCommitTitleOrNote(LANDMARK_INFO_TYPE type) +void LLPanelPlaceInfo::toggleLandmarkEditMode(BOOL enabled) { - LLInventoryItem* item = gInventory.getItem(mLandmarkID); - if (!item) - return; - - std::string current_value; - std::string item_value; - if (type == TITLE) + // If switching to edit mode while creating landmark + // the "Create Landmark" title remains. + if (enabled && mInfoType != CREATE_LANDMARK) { - if (mTitleEditor) - { - current_value = mTitleEditor->getText(); - item_value = item->getName(); - } + mTitle->setText(getString("title_edit_landmark")); } else { - if (mNotesEditor) - { - current_value = mNotesEditor->getText(); - item_value = item->getDescription(); - } + mTitle->setText(mCurrentTitle); } - LLStringUtil::trim(current_value); + mTitleEditor->setEnabled(enabled); + mNotesEditor->setReadOnly(!enabled); + mFolderCombo->setVisible(enabled); + getChild<LLTextBox>("folder_lable")->setVisible(enabled); - if (!current_value.empty() && - item_value != current_value && - gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) - { - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + // HACK: To change the text color in a text editor + // when it was enabled/disabled we set the text once again. + mNotesEditor->setText(mNotesEditor->getText()); +} - if (type == TITLE) - { - new_item->rename(current_value); - } - else - { - new_item->setDescription(current_value); - } +const std::string& LLPanelPlaceInfo::getLandmarkTitle() const +{ + return mTitleEditor->getText(); +} - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } +const std::string LLPanelPlaceInfo::getLandmarkNotes() const +{ + return mNotesEditor->getText(); +} + +const LLUUID LLPanelPlaceInfo::getLandmarkFolder() const +{ + return mFolderCombo->getValue().asUUID(); } void LLPanelPlaceInfo::createLandmark(const LLUUID& folder_id) @@ -921,3 +940,91 @@ void LLPanelPlaceInfo::handleVisibilityChange (BOOL new_visibility) } } } + +void LLPanelPlaceInfo::populateFoldersList() +{ + // Collect all folders that can contain landmarks. + LLInventoryModel::cat_array_t cats; + collectLandmarkFolders(cats); + + mFolderCombo->removeall(); + + // Put the "Landmarks" folder first in list. + LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); + const LLViewerInventoryCategory* cat = gInventory.getCategory(landmarks_id); + if (!cat) + { + llwarns << "Cannot find the landmarks folder" << llendl; + } + std::string cat_full_name = getFullFolderName(cat); + mFolderCombo->add(cat_full_name, cat->getUUID()); + + typedef std::vector<folder_pair_t> folder_vec_t; + folder_vec_t folders; + // Sort the folders by their full name. + for (S32 i = 0; i < cats.count(); i++) + { + cat = cats.get(i); + cat_full_name = getFullFolderName(cat); + folders.push_back(folder_pair_t(cat->getUUID(), cat_full_name)); + } + sort(folders.begin(), folders.end(), cmp_folders); + + // Finally, populate the combobox. + for (folder_vec_t::const_iterator it = folders.begin(); it != folders.end(); it++) + mFolderCombo->add(it->second, LLSD(it->first)); +} + +static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) +{ + return left.second < right.second; +} + +static std::string getFullFolderName(const LLViewerInventoryCategory* cat) +{ + std::string name = cat->getName(); + LLUUID parent_id; + + // translate category name, if it's right below the root + // FIXME: it can throw notification about non existent string in strings.xml + if (cat->getParentUUID().notNull() && cat->getParentUUID() == gInventory.getRootFolderID()) + { + LLTrans::findString(name, "InvFolder " + name); + } + + // we don't want "My Inventory" to appear in the name + while ((parent_id = cat->getParentUUID()).notNull() && parent_id != gInventory.getRootFolderID()) + { + cat = gInventory.getCategory(parent_id); + name = cat->getName() + "/" + name; + } + + return name; +} + +static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats) +{ + LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); + + // Add descendent folders of the "Landmarks" category. + LLInventoryModel::item_array_t items; // unused + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf( + landmarks_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_category); + + // Add the "My Favorites" category. + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + LLViewerInventoryCategory* favorites_cat = gInventory.getCategory(favorites_id); + if (!favorites_cat) + { + llwarns << "Cannot find the favorites folder" << llendl; + } + else + { + cats.put(favorites_cat); + } +} diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 23a845bc20..49aa195490 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -42,6 +42,7 @@ #include "llremoteparcelrequest.h" class LLButton; +class LLComboBox; class LLInventoryItem; class LLLineEditor; class LLPanelPick; @@ -117,18 +118,19 @@ public: const std::string& first, const std::string& last); + void toggleLandmarkEditMode(BOOL enabled); + + const std::string& getLandmarkTitle() const; + const std::string getLandmarkNotes() const; + const LLUUID getLandmarkFolder() const; + /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); /*virtual*/ void handleVisibilityChange (BOOL new_visibility); private: - enum LANDMARK_INFO_TYPE - { - TITLE, - NOTE - }; - void onCommitTitleOrNote(LANDMARK_INFO_TYPE type); + void populateFoldersList(); LLUUID mParcelID; LLUUID mRequestedID; @@ -182,6 +184,7 @@ private: LLTextBox* mCreated; LLLineEditor* mTitleEditor; LLTextEditor* mNotesEditor; + LLComboBox* mFolderCombo; LLPanel* mScrollingPanel; LLPanel* mInfoPanel; LLMediaPanel* mMediaPanel; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 80ecc95afb..35206f54c7 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -40,16 +40,19 @@ #include "lllandmark.h" #include "llparcel.h" +#include "llcombobox.h" +#include "llfiltereditor.h" #include "llfloaterreg.h" #include "llnotifications.h" -#include "llfiltereditor.h" #include "lltabcontainer.h" +#include "lltexteditor.h" #include "lltrans.h" #include "lluictrlfactory.h" #include "llagent.h" #include "llavatarpropertiesprocessor.h" #include "llfloaterworldmap.h" +#include "llinventorybridge.h" #include "llinventorymodel.h" #include "lllandmarkactions.h" #include "lllandmarklist.h" @@ -74,9 +77,6 @@ static const std::string TELEPORT_HISTORY_INFO_TYPE = "teleport_history"; // Helper functions static bool is_agent_in_selected_parcel(LLParcel* parcel); -static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right); -static std::string getFullFolderName(const LLViewerInventoryCategory* cat); -static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats); static void onSLURLBuilt(std::string& slurl); static void setAllChildrenVisible(LLView* view, BOOL visible); @@ -125,8 +125,8 @@ LLPanelPlaces::LLPanelPlaces() mItem(NULL), mPlaceMenu(NULL), mLandmarkMenu(NULL), - mLandmarkFoldersMenuHandle(), - mPosGlobal() + mPosGlobal(), + isLandmarkEditModeOn(false) { mParcelObserver = new LLPlacesParcelObserver(this); mInventoryObserver = new LLPlacesInventoryObserver(this); @@ -146,20 +146,12 @@ LLPanelPlaces::~LLPanelPlaces() LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver); - LLView::deleteViewByHandle(mLandmarkFoldersMenuHandle); - delete mInventoryObserver; delete mParcelObserver; } BOOL LLPanelPlaces::postBuild() { - mCreateLandmarkBtn = getChild<LLButton>("create_landmark_btn"); - mCreateLandmarkBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onCreateLandmarkButtonClicked, this, LLUUID())); - - mFolderMenuBtn = getChild<LLButton>("folder_menu_btn"); - mFolderMenuBtn->setClickedCallback(boost::bind(&LLPanelPlaces::showLandmarkFoldersMenu, this)); - mTeleportBtn = getChild<LLButton>("teleport_btn"); mTeleportBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onTeleportButtonClicked, this)); @@ -169,6 +161,18 @@ BOOL LLPanelPlaces::postBuild() mShareBtn = getChild<LLButton>("share_btn"); //mShareBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onShareButtonClicked, this)); + mEditBtn = getChild<LLButton>("edit_btn"); + mEditBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); + + mSaveBtn = getChild<LLButton>("save_btn"); + mSaveBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onSaveButtonClicked, this)); + + mCancelBtn = getChild<LLButton>("cancel_btn"); + mCancelBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onCancelButtonClicked, this)); + + mCloseBtn = getChild<LLButton>("close_btn"); + mCloseBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); + mOverflowBtn = getChild<LLButton>("overflow_btn"); mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this)); @@ -200,10 +204,18 @@ BOOL LLPanelPlaces::postBuild() } mPlaceInfo = getChild<LLPanelPlaceInfo>("panel_place_info"); - + LLButton* back_btn = mPlaceInfo->getChild<LLButton>("back_btn"); back_btn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); + LLLineEditor* title_editor = mPlaceInfo->getChild<LLLineEditor>("title_editor"); + title_editor->setKeystrokeCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this), NULL); + + LLTextEditor* notes_editor = mPlaceInfo->getChild<LLTextEditor>("notes_editor"); + notes_editor->setKeystrokeCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); + + LLComboBox* folder_combo = mPlaceInfo->getChild<LLComboBox>("folder_combo"); + folder_combo->setSelectionCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this)); return TRUE; } @@ -217,6 +229,7 @@ void LLPanelPlaces::onOpen(const LLSD& key) mPlaceInfoType = key["type"].asString(); mPosGlobal.setZero(); + mItem = NULL; togglePlaceInfoPanel(TRUE); updateVerbs(); @@ -227,11 +240,25 @@ void LLPanelPlaces::onOpen(const LLSD& key) else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) { mPlaceInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK); + + if (key.has("x") && key.has("y") && key.has("z")) + { + mPosGlobal = LLVector3d(key["x"].asReal(), + key["y"].asReal(), + key["z"].asReal()); + } + else + { + mPosGlobal = gAgent.getPositionGlobal(); + } + + mPlaceInfo->displayParcelInfo(LLUUID(), mPosGlobal); } else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { - LLUUID item_uuid = key["id"].asUUID(); - LLInventoryItem* item = gInventory.getItem(item_uuid); + mPlaceInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); + + LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); if (!item) return; @@ -272,8 +299,7 @@ void LLPanelPlaces::onOpen(const LLSD& key) // Start using LLViewerParcelMgr for land selection if // information about nearby land is requested. // Otherwise stop using land selection and deselect land. - if (mPlaceInfoType == AGENT_INFO_TYPE || - mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) + if (mPlaceInfoType == AGENT_INFO_TYPE) { parcel_mgr->addObserver(mParcelObserver); parcel_mgr->selectParcelAt(gAgent.getPositionGlobal()); @@ -291,7 +317,7 @@ void LLPanelPlaces::onOpen(const LLSD& key) void LLPanelPlaces::setItem(LLInventoryItem* item) { - if (!mPlaceInfo) + if (!item) return; mItem = item; @@ -304,7 +330,9 @@ void LLPanelPlaces::setItem(LLInventoryItem* item) return; } - mPlaceInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); + if (!mPlaceInfo) + return; + mPlaceInfo->displayItemInfo(mItem); LLLandmark* lm = gLandmarkList.getAsset(mItem->getAssetUUID(), @@ -324,6 +352,12 @@ void LLPanelPlaces::onLandmarkLoaded(LLLandmark* landmark) landmark->getRegionID(region_id); landmark->getGlobalPos(mPosGlobal); mPlaceInfo->displayParcelInfo(region_id, mPosGlobal); + + // Check if item is in agent's inventory and he has the permission to modify it. + BOOL is_landmark_editable = mItem.notNull() && + gInventory.isObjectDescendentOf(mItem->getUUID(), gInventory.getRootFolderID()) && + mItem->getPermissions().allowModifyBy(gAgent.getID()); + mEditBtn->setEnabled(is_landmark_editable); } void LLPanelPlaces::onFilterEdit(const std::string& search_string) @@ -436,6 +470,136 @@ void LLPanelPlaces::onShowOnMapButtonClicked() } } +void LLPanelPlaces::onEditButtonClicked() +{ + if (!mPlaceInfo || isLandmarkEditModeOn) + return; + + isLandmarkEditModeOn = true; + + mPlaceInfo->toggleLandmarkEditMode(TRUE); + + updateVerbs(); +} + +void LLPanelPlaces::onSaveButtonClicked() +{ + if (!mPlaceInfo || mItem.isNull()) + return; + + LLAssetType::EType item_type = mItem->getType(); + if (item_type == LLAssetType::AT_LANDMARK || item_type != LLAssetType::AT_LINK) + { + // If the item is a link get a linked item + if (item_type == LLAssetType::AT_LINK) + { + mItem = gInventory.getItem(mItem->getAssetUUID()); + if (mItem.isNull()) + return; + } + } + else + { + return; + } + + std::string current_title_value = mPlaceInfo->getLandmarkTitle(); + std::string item_title_value = mItem->getName(); + std::string current_notes_value = mPlaceInfo->getLandmarkNotes(); + std::string item_notes_value = mItem->getDescription(); + + LLStringUtil::trim(current_title_value); + LLStringUtil::trim(current_notes_value); + + bool is_item_update_needed = false; + + if (!current_title_value.empty() && + (item_title_value != current_title_value || item_notes_value != current_notes_value)) + { + is_item_update_needed = true; + } + + LLUUID item_id = mItem->getUUID(); + LLUUID folder_id = mPlaceInfo->getLandmarkFolder(); + + // Check if item is in agent's inventory and he has the permission to modify it. + if (!gInventory.isObjectDescendentOf(item_id, gInventory.getRootFolderID()) || + !mItem->getPermissions().allowModifyBy(gAgent.getID())) + return; + + if(folder_id != mItem->getParentUUID() || is_item_update_needed) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)mItem.get(); + LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); + + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + + // If target is the favorites folder we create link to it. + if (favorites_id == folder_id) + { + if (is_item_update_needed) + { + new_item->rename(current_title_value); + new_item->setDescription(current_notes_value); + new_item->updateServer(FALSE); + + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + + link_inventory_item(gAgent.getID(), + item->getUUID(), + folder_id, + item->getName(), + LLAssetType::AT_LINK, + LLPointer<LLInventoryCallback>(NULL)); + } + else + { + if (is_item_update_needed) + { + new_item->rename(current_title_value); + new_item->setDescription(current_notes_value); + new_item->updateServer(FALSE); + } + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(folder_id, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + new_item->setParent(folder_id); + new_item->updateParentOnServer(FALSE); + + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + } + + onCancelButtonClicked(); +} + +void LLPanelPlaces::onCancelButtonClicked() +{ + if (!mPlaceInfo) + return; + + if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) + { + onBackButtonClicked(); + } + else + { + mPlaceInfo->toggleLandmarkEditMode(FALSE); + updateVerbs(); + + // Reload the landmark properties. + mPlaceInfo->displayItemInfo(mItem); + } +} + void LLPanelPlaces::onOverflowButtonClicked() { LLToggleableMenu* menu; @@ -487,7 +651,12 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) std::string item = param.asString(); if (item == "landmark") { - onOpen(LLSD().insert("type", CREATE_LANDMARK_INFO_TYPE)); + LLSD key; + key["type"] = CREATE_LANDMARK_INFO_TYPE; + key["x"] = mPosGlobal.mdV[VX]; + key["y"] = mPosGlobal.mdV[VY]; + key["z"] = mPosGlobal.mdV[VZ]; + onOpen(key); } else if (item == "copy") { @@ -523,20 +692,6 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) } } -void LLPanelPlaces::onCreateLandmarkButtonClicked(const LLUUID& folder_id) -{ - if (!mPlaceInfo) - return; - - // To prevent creating duplicate landmarks - // disable landmark creating buttons until - // the information on existing landmarks is reloaded. - mCreateLandmarkBtn->setEnabled(FALSE); - mFolderMenuBtn->setEnabled(FALSE); - - mPlaceInfo->createLandmark(folder_id); -} - void LLPanelPlaces::onBackButtonClicked() { if (!mPlaceInfo) @@ -697,10 +852,14 @@ void LLPanelPlaces::updateVerbs() bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE; bool is_media_panel_visible = mPlaceInfo->isMediaPanelVisible(); - mTeleportBtn->setVisible(!is_create_landmark_visible); - mShareBtn->setVisible(!is_create_landmark_visible); - mCreateLandmarkBtn->setVisible(is_create_landmark_visible); - mFolderMenuBtn->setVisible(is_create_landmark_visible); + mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); + mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); + mShareBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); + mOverflowBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); + mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn); + mSaveBtn->setVisible(isLandmarkEditModeOn); + mCancelBtn->setVisible(isLandmarkEditModeOn); + mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); mOverflowBtn->setEnabled(is_place_info_visible && !is_media_panel_visible && !is_create_landmark_visible); @@ -714,15 +873,6 @@ void LLPanelPlaces::updateVerbs() !mPosGlobal.isExactlyZero() && !LLViewerParcelMgr::getInstance()->inAgentParcel(mPosGlobal)); } - else if (is_create_landmark_visible) - { - // Enable "Create Landmark" only if there is no landmark - // for the current parcel and agent is inside it. - bool enable = !LLLandmarkActions::landmarkAlreadyExists() && - is_agent_in_selected_parcel(mParcel->getParcel()); - mCreateLandmarkBtn->setEnabled(enable); - mFolderMenuBtn->setEnabled(enable); - } else if (mPlaceInfoType == LANDMARK_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) { mTeleportBtn->setEnabled(TRUE); @@ -735,131 +885,8 @@ void LLPanelPlaces::updateVerbs() if (mActivePanel) mActivePanel->updateVerbs(); } -} - -void LLPanelPlaces::showLandmarkFoldersMenu() -{ - if (mLandmarkFoldersMenuHandle.isDead()) - { - LLToggleableMenu::Params menu_p; - menu_p.name("landmarks_folders_menu"); - menu_p.can_tear_off(false); - menu_p.visible(false); - menu_p.scrollable(true); - menu_p.max_scrollable_items = 10; - - LLToggleableMenu* menu = LLUICtrlFactory::create<LLToggleableMenu>(menu_p); - - mLandmarkFoldersMenuHandle = menu->getHandle(); - } - - LLToggleableMenu* menu = (LLToggleableMenu*)mLandmarkFoldersMenuHandle.get(); - if(!menu) - return; - - if (!menu->toggleVisibility()) - return; - - // Collect all folders that can contain landmarks. - LLInventoryModel::cat_array_t cats; - collectLandmarkFolders(cats); - - // Sort the folders by their full name. - folder_vec_t folders; - S32 count = cats.count(); - for (S32 i = 0; i < count; i++) - { - const LLViewerInventoryCategory* cat = cats.get(i); - std::string cat_full_name = getFullFolderName(cat); - folders.push_back(folder_pair_t(cat->getUUID(), cat_full_name)); - } - sort(folders.begin(), folders.end(), cmp_folders); - - LLRect btn_rect = mFolderMenuBtn->getRect(); - - LLRect root_rect = getRootView()->getRect(); - - // Check it there are changed items or viewer dimensions - // have changed since last call - if (mLandmarkFoldersCache.size() == count && - mRootViewWidth == root_rect.getWidth() && - mRootViewHeight == root_rect.getHeight()) - { - S32 i; - for (i = 0; i < count; i++) - { - if (mLandmarkFoldersCache[i].second != folders[i].second) - { - break; - } - } - - // Check passed, just show the menu - if (i == count) - { - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - - menu->setButtonRect(btn_rect, this); - LLMenuGL::showPopup(this, menu, btn_rect.mRight, btn_rect.mTop); - return; - } - } - - // If there are changes, store the new viewer dimensions - // and a list of folders - mRootViewWidth = root_rect.getWidth(); - mRootViewHeight = root_rect.getHeight(); - mLandmarkFoldersCache = folders; - - menu->empty(); - - // Menu width must not exceed the root view limits, - // so we assume the space between the left edge of - // the root view and - LLRect screen_btn_rect; - localRectToScreen(btn_rect, &screen_btn_rect); - S32 free_space = screen_btn_rect.mRight; - U32 max_width = llmin(LANDMARK_FOLDERS_MENU_WIDTH, free_space); - for(folder_vec_t::const_iterator it = mLandmarkFoldersCache.begin(); it != mLandmarkFoldersCache.end(); it++) - { - const std::string& item_name = it->second; - - LLMenuItemCallGL::Params item_params; - item_params.name(item_name); - item_params.label(item_name); - - item_params.on_click.function(boost::bind(&LLPanelPlaces::onCreateLandmarkButtonClicked, this, it->first)); - - LLMenuItemCallGL *menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); - - // *TODO: Use a separate method for menu width calculation. - // Check whether item name wider than menu - if (menu_item->getNominalWidth() > max_width) - { - S32 chars_total = item_name.length(); - S32 chars_fitted = 1; - menu_item->setLabel(LLStringExplicit("")); - S32 label_space = max_width - menu_item->getFont()->getWidth("...") - - menu_item->getNominalWidth(); // This returns width of menu item with empty label (pad pixels) - - while (chars_fitted < chars_total && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) - { - chars_fitted++; - } - chars_fitted--; // Rolling back one char, that doesn't fit - - menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); - } - - menu->addChild(menu_item); - } - - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - menu->setButtonRect(btn_rect, this); - LLMenuGL::showPopup(this, menu, btn_rect.mRight, btn_rect.mTop); + isLandmarkEditModeOn = false; } static bool is_agent_in_selected_parcel(LLParcel* parcel) @@ -874,70 +901,6 @@ static bool is_agent_in_selected_parcel(LLParcel* parcel) parcel->getLocalID() == parcel_mgr->getAgentParcel()->getLocalID(); } -static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) -{ - return left.second < right.second; -} - -static std::string getFullFolderName(const LLViewerInventoryCategory* cat) -{ - std::string name = cat->getName(); - LLUUID parent_id; - - // translate category name, if it's right below the root - // FIXME: it can throw notification about non existent string in strings.xml - if (cat->getParentUUID().notNull() && cat->getParentUUID() == gInventory.getRootFolderID()) - { - LLTrans::findString(name, "InvFolder " + name); - } - - // we don't want "My Inventory" to appear in the name - while ((parent_id = cat->getParentUUID()).notNull() && parent_id != gInventory.getRootFolderID()) - { - cat = gInventory.getCategory(parent_id); - name = cat->getName() + "/" + name; - } - - return name; -} - -static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats) -{ - // Add the "Landmarks" category itself. - LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); - LLViewerInventoryCategory* landmarks_cat = gInventory.getCategory(landmarks_id); - if (!landmarks_cat) - { - llwarns << "Cannot find the landmarks folder" << llendl; - } - else - { - cats.put(landmarks_cat); - } - - // Add descendent folders of the "Landmarks" category. - LLInventoryModel::item_array_t items; // unused - LLIsType is_category(LLAssetType::AT_CATEGORY); - gInventory.collectDescendentsIf( - landmarks_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_category); - - // Add the "My Favorites" category. - LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); - LLViewerInventoryCategory* favorites_cat = gInventory.getCategory(favorites_id); - if (!favorites_cat) - { - llwarns << "Cannot find the favorites folder" << llendl; - } - else - { - cats.put(favorites_cat); - } -} - static void onSLURLBuilt(std::string& slurl) { LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index f208e91237..0b3b3b5fc3 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -72,6 +72,9 @@ private: //void onShareButtonClicked(); void onTeleportButtonClicked(); void onShowOnMapButtonClicked(); + void onEditButtonClicked(); + void onSaveButtonClicked(); + void onCancelButtonClicked(); void onOverflowButtonClicked(); void onOverflowMenuItemClicked(const LLSD& param); void onCreateLandmarkButtonClicked(const LLUUID& folder_id); @@ -84,8 +87,6 @@ private: void onAgentParcelChange(); void updateVerbs(); - void showLandmarkFoldersMenu(); - LLFilterEditor* mFilterEditor; LLPanelPlacesTab* mActivePanel; LLTabContainer* mTabContainer; @@ -94,11 +95,13 @@ private: LLToggleableMenu* mPlaceMenu; LLToggleableMenu* mLandmarkMenu; - LLButton* mCreateLandmarkBtn; - LLButton* mFolderMenuBtn; LLButton* mTeleportBtn; LLButton* mShowOnMapBtn; LLButton* mShareBtn; + LLButton* mEditBtn; + LLButton* mSaveBtn; + LLButton* mCancelBtn; + LLButton* mCloseBtn; LLButton* mOverflowBtn; LLPlacesInventoryObserver* mInventoryObserver; @@ -118,19 +121,7 @@ private: // Information type currently shown in Place Information panel std::string mPlaceInfoType; - // Menu handle for pop-up menu to chose a landmark saving - // folder when creating a new landmark - LLHandle<LLView> mLandmarkFoldersMenuHandle; - - typedef std::vector<folder_pair_t> folder_vec_t; - - // List of folders to choose from when creating a landmark - folder_vec_t mLandmarkFoldersCache; - - // If root view width or height is changed - // the pop-up menu must be updated - S32 mRootViewWidth; - S32 mRootViewHeight; + bool isLandmarkEditModeOn; LLSafeHandle<LLParcelSelection> mParcel; }; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 3bd2645be3..cda7942c1d 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -102,7 +102,7 @@ void LLPanelProfile::onOpen(const LLSD& key) { if (key.has("open_tab_name")) { - getTabContainer()[PANEL_PICKS]->onClose(); + getTabContainer()[PANEL_PICKS]->onClosePanel(); // onOpen from selected panel will be called from onTabSelected callback getTabCtrl()->selectTabByName(key["open_tab_name"]); diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 3bda30e0c6..604faf8eb4 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -68,8 +68,6 @@ void LLPreviewAnim::endAnimCallback( void *userdata ) // virtual BOOL LLPreviewAnim::postBuild() { - mCloseSignal.connect(boost::bind(&LLPreviewAnim::onClose, this)); - const LLInventoryItem* item = getItem(); if(item) { @@ -181,7 +179,8 @@ void LLPreviewAnim::auditionAnim( void *userdata ) } } -void LLPreviewAnim::onClose() +// virtual +void LLPreviewAnim::onClose(bool app_quitting) { const LLInventoryItem *item = getItem(); diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index d24e624c32..616c5789ac 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -46,10 +46,10 @@ public: static void auditionAnim( void* userdata ); static void endAnimCallback( void *userdata ); /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); void activate(e_activation_type type); protected: - void onClose(); LLAnimPauseRequest mPauseRequest; LLUUID mItemID; diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index faca950963..32ed20bd56 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -32,10 +32,10 @@ #include "llviewerprecompiledheaders.h" -#include <algorithm> - #include "llpreviewgesture.h" +#include <algorithm> + // libraries #include "lldatapacker.h" #include "lldarray.h" @@ -260,7 +260,8 @@ BOOL LLPreviewGesture::canClose() } } -void LLPreviewGesture::onClose() +// virtual +void LLPreviewGesture::onClose(bool app_quitting) { LLGestureManager::instance().stopGesture(mPreviewGesture); } @@ -354,7 +355,6 @@ LLPreviewGesture::~LLPreviewGesture() BOOL LLPreviewGesture::postBuild() { - mCloseSignal.connect(boost::bind(&LLPreviewGesture::onClose, this)); mVisibleSignal.connect(boost::bind(&LLPreviewGesture::onVisibilityChange, this, _2)); LLLineEditor* edit; diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index 16ac935775..9d26539453 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -70,11 +70,10 @@ public: // LLFloater /*virtual*/ BOOL canClose(); + /*virtual*/ void onClose(bool app_quitting); /*virtual*/ void onUpdateSucceeded(); /*virtual*/ void refresh(); - - protected: // Populate various comboboxes void addModifiers(); @@ -108,7 +107,6 @@ protected: // "Sound", "Chat", or "Wait" LLScrollListItem* addStep(const enum EStepType step_type); - void onClose(); void onVisibilityChange ( const LLSD& new_visibility ); static std::string getLabel(std::vector<std::string> labels); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 26ac95060f..296502ff16 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -273,11 +273,14 @@ public: LLViewerObject* getFirstCopyableObject(BOOL get_parent = FALSE); LLViewerObject* getFirstDeleteableObject(); LLViewerObject* getFirstMoveableObject(BOOL get_parent = FALSE); + + /// Return the object that lead to this selection, possible a child LLViewerObject* getPrimaryObject() { return mPrimaryObject; } // iterate through texture entries template <typename T> bool getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res); - + template <typename T> bool isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value); + void addNode(LLSelectNode *nodep); void addNodeAtEnd(LLSelectNode *nodep); void moveNodeToFront(LLSelectNode *nodep); @@ -783,5 +786,52 @@ template <typename T> bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGet return identical; } +// Templates +//----------------------------------------------------------------------------- +// isMultipleTEValue iterate through all TEs and test for uniqueness +// with certain return value ignored when performing the test. +// e.g. when testing if the selection has a unique non-empty homeurl : +// you can set ignore_value = "" and it will only compare among the non-empty +// homeUrls and ignore the empty ones. +//----------------------------------------------------------------------------- +template <typename T> bool LLObjectSelection::isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value) +{ + bool have_first = false; + T selected_value = T(); + + // Now iterate through all TEs to test for sameness + bool unique = TRUE; + for (iterator iter = begin(); iter != end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + for (S32 te = 0; te < object->getNumTEs(); ++te) + { + if (!node->isTESelected(te)) + { + continue; + } + T value = func->get(object, te); + if(value == ignore_value) + { + continue; + } + if (!have_first) + { + have_first = true; + } + else + { + if (value !=selected_value ) + { + unique = false; + return !unique; + } + } + } + } + return !unique; +} + #endif diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 2bb1e80eb8..c5a92f52d0 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -522,7 +522,7 @@ LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& contactName->setValue(name); mCloseBtn = getChild<LLButton>("hide_btn"); - mCloseBtn->setCommitCallback(boost::bind(&LLSysWellWindow::RowPanel::onClose, this)); + mCloseBtn->setCommitCallback(boost::bind(&LLSysWellWindow::RowPanel::onClosePanel, this)); } //--------------------------------------------------------------------------------- @@ -531,7 +531,7 @@ LLSysWellWindow::RowPanel::~RowPanel() } //--------------------------------------------------------------------------------- -void LLSysWellWindow::RowPanel::onClose() +void LLSysWellWindow::RowPanel::onClosePanel() { gIMMgr->removeSession(mChiclet->getSessionId()); // This row panel will be removed from the list in LLSysWellWindow::sessionRemoved(). diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index 203b949715..0c3f4d0587 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -137,7 +137,7 @@ private: void onMouseLeave(S32 x, S32 y, MASK mask); BOOL handleMouseDown(S32 x, S32 y, MASK mask); private: - void onClose(); + void onClosePanel(); public: LLIMChiclet* mChiclet; private: diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 9fc91e2971..43f82e592b 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -102,15 +102,16 @@ public: virtual ~LLFloaterTexturePicker(); // LLView overrides - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, + /*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 draw(); - virtual BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ void draw(); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); // LLFloater overrides - virtual BOOL postBuild(); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_settings); // New functions void setImageID( const LLUUID& image_asset_id); @@ -130,7 +131,6 @@ public: void commitIfImmediateSet(); void onFilterEdit(const std::string& search_string ); - void onClose(); static void onBtnSetToDefault( void* userdata ); static void onBtnSelect( void* userdata ); @@ -369,7 +369,7 @@ BOOL LLFloaterTexturePicker::handleKeyHere(KEY key, MASK mask) return LLFloater::handleKeyHere(key, mask); } -void LLFloaterTexturePicker::onClose() +void LLFloaterTexturePicker::onClose(bool app_quitting) { if (mOwner) { @@ -381,8 +381,6 @@ void LLFloaterTexturePicker::onClose() // virtual BOOL LLFloaterTexturePicker::postBuild() { - mCloseSignal.connect(boost::bind(&LLFloaterTexturePicker::onClose, this)); - LLFloater::postBuild(); if (!mLabel.empty()) diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index d9be6b172c..e4a3f8603b 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -308,7 +308,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal //gFloaterView->adjustToFitScreen(this, FALSE); if (mLineEditor) { - mLineEditor->setFocus(TRUE); mLineEditor->selectAll(); } if(mDefaultOption >= 0) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 5525c359fc..beb16c267e 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -70,6 +70,7 @@ #include "llworld.h" #include "llui.h" #include "llweb.h" +#include "pipeline.h" // setHighlightObject extern BOOL gDebugClicks; @@ -391,24 +392,24 @@ ECursorType cursor_from_object(LLViewerObject* object) case CLICK_ACTION_SIT: if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->isSitting())) // not already sitting? { - cursor = UI_CURSOR_TOOLSIT; + cursor = UI_CURSOR_HAND; } break; case CLICK_ACTION_BUY: - cursor = UI_CURSOR_TOOLBUY; + cursor = UI_CURSOR_HAND; break; case CLICK_ACTION_OPEN: // Open always opens the parent. if (parent && parent->allowOpen()) { - cursor = UI_CURSOR_TOOLOPEN; + cursor = UI_CURSOR_HAND; } break; case CLICK_ACTION_PAY: if ((object && object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) { - cursor = UI_CURSOR_TOOLPAY; + cursor = UI_CURSOR_HAND; } break; case CLICK_ACTION_PLAY: @@ -472,7 +473,9 @@ void LLToolPie::selectionPropertiesReceived() BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE); - + + // Show screen-space highlight glow effect + bool show_highlight = false; LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); @@ -483,24 +486,28 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) if (object && useClickAction(mask, object, parent)) { + show_highlight = true; ECursorType cursor = cursor_from_object(object); gViewerWindow->setCursor(cursor); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } else if (handleMediaHover(mHoverPick)) { + show_highlight = true; // cursor set by media object lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } else if ((object && !object->isAvatar() && object->usePhysics()) || (parent && !parent->isAvatar() && parent->usePhysics())) { + show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } else if ( (object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) { + show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_HAND); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } @@ -519,6 +526,15 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) } } + static LLCachedControl<bool> enable_highlight( + gSavedSettings, "RenderHighlightEnable", false); + LLDrawable* drawable = NULL; + if (enable_highlight && show_highlight && object) + { + drawable = object->mDrawable; + } + gPipeline.setHighlightObject(drawable); + return TRUE; } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 0b21f3565d..8c46949d70 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -83,7 +83,7 @@ #include "llfloaternamedesc.h" #include "llfloaternotificationsconsole.h" #include "llfloateropenobject.h" -#include "llgivemoney.h" +#include "llfloaterpay.h" #include "llfloaterparcel.h" #include "llfloaterperms.h" #include "llfloaterpostcard.h" @@ -195,8 +195,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); LLFloaterReg::add("parcel_info", "floater_preview_url.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterParcelInfo>); - LLFloaterReg::add("pay_resident", "floater_pay.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPay>); - LLFloaterReg::add("pay_object", "floater_pay_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPay>); + LLFloaterPayUtil::registerFloater(); LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostcard>); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2b972614f1..2f55be8b9c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -588,7 +588,9 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, mHasFocus(false), mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), mDoNavigateOnLoad(false), + mDoNavigateOnLoadRediscoverType(false), mDoNavigateOnLoadServerRequest(false), + mMediaSourceFailedInit(false), mIsUpdated(false) { @@ -664,7 +666,7 @@ void LLViewerMediaImpl::createMediaSource() { if(! mMediaURL.empty()) { - navigateTo(mMediaURL, mMimeType, false, mDoNavigateOnLoadServerRequest); + navigateTo(mMediaURL, mMimeType, mDoNavigateOnLoadRediscoverType, mDoNavigateOnLoadServerRequest); } else if(! mMimeType.empty()) { @@ -703,7 +705,7 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type) LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height) { std::string plugin_basename = LLMIMETypes::implType(media_type); - + if(plugin_basename.empty()) { LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; @@ -774,6 +776,9 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) return false; } + // If we got here, we want to ignore previous init failures. + mMediaSourceFailedInit = false; + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight); if (media_source) @@ -787,6 +792,9 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) return true; } + // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes. + mMediaSourceFailedInit = true; + return false; } @@ -1003,14 +1011,7 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateHome() { - mMediaURL = mHomeURL; - mDoNavigateOnLoad = !mMediaURL.empty(); - mDoNavigateOnLoadServerRequest = false; - - if(mMediaSource) - { - mMediaSource->loadURI( mHomeURL ); - } + navigateTo(mHomeURL, "", true, false); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1025,12 +1026,16 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi setNavState(MEDIANAVSTATE_NONE); } - // Always set the current URL. + // Always set the current URL and MIME type. mMediaURL = url; + mMimeType = mime_type; // If the current URL is not null, make the instance do a navigate on load. mDoNavigateOnLoad = !mMediaURL.empty(); + // if mime type discovery was requested, we'll need to do it when the media loads + mDoNavigateOnLoadRediscoverType = rediscover_type; + // and if this was a server request, the navigate on load will also need to be one. mDoNavigateOnLoadServerRequest = server_request; @@ -1041,6 +1046,21 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi return; } + + // If the caller has specified a non-empty MIME type, look that up in our MIME types list. + // If we have a plugin for that MIME type, use that instead of attempting auto-discovery. + // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type + // but the parcel owner has correctly set the MIME type in the parcel media settings. + + if(!mMimeType.empty() && (mMimeType != "none/none")) + { + std::string plugin_basename = LLMIMETypes::implType(mMimeType); + if(!plugin_basename.empty()) + { + // We have a plugin for this mime type + rediscover_type = false; + } + } if(rediscover_type) { @@ -1147,7 +1167,7 @@ bool LLViewerMediaImpl::canNavigateBack() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::update() { - if(mMediaSource == NULL) + if(mMediaSource == NULL && !mMediaSourceFailedInit) { if(mPriority != LLPluginClassMedia::PRIORITY_UNLOADED) { @@ -1374,6 +1394,18 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla { switch(event) { + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + // The plugin failed to load properly. Make sure the timer doesn't retry. + mMediaSourceFailedInit = true; + + // TODO: may want a different message for this case? + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mMimeType); + LLNotifications::instance().add("MediaPluginFailed", args); + } + break; + case MEDIA_EVENT_PLUGIN_FAILED: { LLSD args; @@ -1422,7 +1454,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: { LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; - setNavState(MEDIANAVSTATE_NONE); } break; diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index c9ba5841e9..37aabcf2d6 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -278,7 +278,9 @@ public: bool mHasFocus; LLPluginClassMedia::EPriority mPriority; bool mDoNavigateOnLoad; + bool mDoNavigateOnLoadRediscoverType; bool mDoNavigateOnLoadServerRequest; + bool mMediaSourceFailedInit; private: diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index f9377ab37b..1b1b7cedb1 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -304,7 +304,11 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) BOOL retval = FALSE; if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia()) { - mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks); + // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y. + // The latter is the position of the mouse at the time of the event + // The former is the 'scroll amount' in x and y, respectively. + // All we have for 'scroll amount' here is 'clicks', and no mask. + mMediaImpl->getMediaPlugin()->scrollEvent(0, clicks, /*mask*/0); retval = TRUE; } return retval; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d95992412f..dde7b1c7ee 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -111,6 +111,7 @@ #include "llfloaterlandholdings.h" #include "llfloatermap.h" #include "llfloateropenobject.h" +#include "llfloaterpay.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" @@ -129,7 +130,6 @@ #include "llavataractions.h" #include "lllandmarkactions.h" #include "llmemoryview.h" -#include "llgivemoney.h" #include "llgroupmgr.h" #include "lltooltip.h" #include "llhudeffecttrail.h" @@ -567,6 +567,15 @@ void init_menus() gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); +#if !MEM_TRACK_MEM + // Don't display the Memory console menu if the feature is turned off + LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); + if (memoryMenu) + { + memoryMenu->setVisible(FALSE); + } +#endif + gMenuBarView->createJumpKeys(); // Let land based option enable when parcel changes @@ -5405,7 +5414,7 @@ class LLAvatarAddContact : public view_listener_t } }; -bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle) +bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) { S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) @@ -5413,7 +5422,7 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec gAgent.clearBusy(); } - LLViewerObject* objectp = handle->getPrimaryObject(); + LLViewerObject* objectp = selection->getPrimaryObject(); // Show avatar's name if paying attachment if (objectp && objectp->isAttachment()) @@ -5428,14 +5437,14 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec { if (objectp->isAvatar()) { - const BOOL is_group = FALSE; - LLFloaterPay::payDirectly(&give_money, + const bool is_group = false; + LLFloaterPayUtil::payDirectly(&give_money, objectp->getID(), is_group); } else { - LLFloaterPay::payViaObject(&give_money, objectp->getID()); + LLFloaterPayUtil::payViaObject(&give_money, selection); } } return false; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 2e8580907e..aa662b713e 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -98,6 +98,7 @@ #include "llnotifications.h" #include "llnotify.h" #include "llpanelgrouplandmoney.h" +#include "llpanelplaces.h" #include "llrecentpeople.h" #include "llselectmgr.h" #include "llsidetray.h" @@ -138,7 +139,6 @@ #include "llkeythrottle.h" #include "llgroupactions.h" #include "llagentui.h" -#include "llsidetray.h" #include "llpanelblockedlist.h" #include "llpanelplaceinfo.h" @@ -907,14 +907,15 @@ void open_offer(const std::vector<LLUUID>& items, const std::string& from_name) LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); LLSD args; args["LANDMARK_NAME"] = item->getName(); - args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unnkown"); + args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown"); LLNotifications::instance().add("LandmarkCreated", args); - - // Open new landmark for editing in Places panel. - LLSD key; - key["type"] = "landmark"; - key["id"] = item->getUUID(); - LLSideTray::getInstance()->showPanel("panel_places", key); + + // Created landmark is passed to Places panel to allow its editing. + LLPanelPlaces *panel = dynamic_cast<LLPanelPlaces*>(LLSideTray::getInstance()->showPanel("panel_places", LLSD())); + if (panel) + { + panel->setItem(item); + } } break; case LLAssetType::AT_TEXTURE: diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 05011a1568..1f4f1322fd 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -47,7 +47,6 @@ #include "llframetimer.h" #include "llinventory.h" #include "llmaterialtable.h" -#include "llmediadataresponder.h" #include "llmutelist.h" #include "llnamevalue.h" #include "llprimitive.h" diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index a3f9c839a0..9bcdcbf9ad 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -226,11 +226,13 @@ void LLViewerParcelMedia::play(LLParcel* parcel) media_height, media_auto_scale, media_loop); - sMediaImpl->navigateTo(media_url); + sMediaImpl->navigateTo(media_url, mime_type, true); } } else { + LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; + // There is no media impl, make a new one sMediaImpl = LLViewerMedia::newMediaImpl( placeholder_texture_id, @@ -238,7 +240,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel) media_height, media_auto_scale, media_loop); - sMediaImpl->navigateTo(media_url); + sMediaImpl->navigateTo(media_url, mime_type, true); } LLFirstUse::useMedia(); @@ -544,6 +546,12 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; }; break; + + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; + }; + break; }; } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 6401389c8f..3c1ac3d571 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -6921,7 +6921,8 @@ void LLVoiceClient::notifyFriendObservers() void LLVoiceClient::lookupName(const LLUUID &id) { - gCacheName->get(id, FALSE, &LLVoiceClient::onAvatarNameLookup); + BOOL is_group = FALSE; + gCacheName->get(id, is_group, &LLVoiceClient::onAvatarNameLookup); } //static diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e69779b2dc..1704f63376 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -46,7 +46,6 @@ #include "llvolumemessage.h" #include "material_codes.h" #include "message.h" -#include "llmediadataresponder.h" #include "llpluginclassmedia.h" // for code in the mediaEvent handler #include "object_flags.h" #include "llagentconstants.h" @@ -69,7 +68,7 @@ #include "pipeline.h" #include "llsdutil.h" #include "llmediaentry.h" -#include "llmediadatafetcher.h" +#include "llmediadataclient.h" #include "llagent.h" const S32 MIN_QUIET_FRAMES_COALESCE = 30; @@ -86,10 +85,63 @@ F32 LLVOVolume::sLODFactor = 1.f; F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop F32 LLVOVolume::sDistanceFactor = 1.0f; S32 LLVOVolume::sNumLODChanges = 0; +LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL; +LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL; static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); +// Implementation class of LLMediaDataClientObject. See llmediadataclient.h +class LLMediaDataClientObjectImpl : public LLMediaDataClientObject +{ +public: + LLMediaDataClientObjectImpl(LLVOVolume *obj) : mObject(obj) {} + LLMediaDataClientObjectImpl() { mObject = NULL; } + + virtual U8 getMediaDataCount() const + { return mObject->getNumTEs(); } + + virtual LLSD getMediaDataLLSD(U8 index) const + { + LLSD result; + LLTextureEntry *te = mObject->getTE(index); + if (NULL != te) + { + llassert((te->getMediaData() != NULL) == te->hasMedia()); + if (te->getMediaData() != NULL) + { + result = te->getMediaData()->asLLSD(); + } + } + return result; + } + + virtual LLUUID getID() const + { return mObject->getID(); } + + virtual void mediaNavigateBounceBack(U8 index) + { mObject->mediaNavigateBounceBack(index); } + + virtual bool hasMedia() const + { return mObject->hasMedia(); } + + virtual void updateObjectMediaData(LLSD const &data) + { mObject->updateObjectMediaData(data); } + + virtual F64 getDistanceFromAvatar() const + { return mObject->getRenderPosition().length(); } + + virtual F64 getTotalMediaInterest() const + { return mObject->getTotalMediaInterest(); } + + virtual std::string getCapabilityUrl(const std::string &name) const + { return mObject->getRegion()->getCapability(name); } + +private: + LLPointer<LLVOVolume> mObject; +}; + + LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLViewerObject(id, pcode, regionp), mVolumeImpl(NULL) @@ -133,13 +185,19 @@ LLVOVolume::~LLVOVolume() // static void LLVOVolume::initClass() { - LLMediaDataFetcher::initClass(); + // gSavedSettings better be around + const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay"); + const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay"); + const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries"); + sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries); + sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay, max_retries); } // static void LLVOVolume::cleanupClass() { - LLMediaDataFetcher::cleanupClass(); + sObjectMediaClient = NULL; + sObjectMediaNavigateClient = NULL; } U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, @@ -316,13 +374,23 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, } } } - if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) { - // If the media changed at all, request new media data - if(mMedia) + if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) + { + // If only the media URL changed, and it isn't a media version URL, + // ignore it + if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) && + mMedia && ! mMedia->mMediaURL.empty() && + ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) ) { - llinfos << "Media URL: " << mMedia->mMediaURL << llendl; + // If the media changed at all, request new media data + LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " << + ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL; + requestMediaDataUpdate(); } - requestMediaDataUpdate(); + else { + LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " << + ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL; + } } // ...and clean up any media impls cleanUpMediaImpls(); @@ -1621,7 +1689,7 @@ bool LLVOVolume::hasMedia() const void LLVOVolume::requestMediaDataUpdate() { - LLMediaDataFetcher::fetchMedia(this); + sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this)); } void LLVOVolume::cleanUpMediaImpls() @@ -1700,6 +1768,72 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m // << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; } +void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) +{ + // Find the media entry for this navigate + const LLMediaEntry* mep = NULL; + viewer_media_t impl = getMediaImpl(texture_index); + LLTextureEntry *te = getTE(texture_index); + if(te) + { + mep = te->getMediaData(); + } + + if (mep && impl) + { + std::string url = mep->getCurrentURL(); + if (url.empty()) + { + url = mep->getHomeURL(); + } + if (! url.empty()) + { + LL_INFOS("LLMediaDataClient") << "bouncing back to URL: " << url << LL_ENDL; + impl->navigateTo(url, "", false, true); + } + } +} + +bool LLVOVolume::hasNavigatePermission(const LLMediaEntry* media_entry) +{ + // NOTE: This logic duplicates the logic in the server (in particular, in llmediaservice.cpp). + if (NULL == media_entry ) return false; // XXX should we assert here? + + // The agent has permissions to navigate if: + // - agent has edit permissions, or + // - world permissions are on, or + // - group permissions are on, and agent_id is in the group, or + // - agent permissions are on, and agent_id is the owner + + if (permModify()) + { + return true; + } + + U8 media_perms = media_entry->getPermsInteract(); + + // World permissions + if (0 != (media_perms & LLMediaEntry::PERM_ANYONE)) + { + return true; + } + + // Group permissions + else if (0 != (media_perms & LLMediaEntry::PERM_GROUP) && permGroupOwner()) + { + return true; + } + + // Owner permissions + else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner()) + { + return true; + } + + return false; + +} + void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) { switch(event) @@ -1733,6 +1867,10 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, { block_navigation = true; } + if (!block_navigation && !hasNavigatePermission(mep)) + { + block_navigation = true; + } } else { @@ -1744,29 +1882,14 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, llinfos << "blocking navigate to URI " << new_location << llendl; // "bounce back" to the current URL from the media entry - // NOTE: the only way block_navigation can be true is if we found the media entry, so we're guaranteed here that mep is not NULL. - impl->navigateTo(mep->getCurrentURL()); + mediaNavigateBounceBack(face_index); } else { llinfos << "broadcasting navigate with URI " << new_location << llendl; - // Post the navigate to the cap - std::string cap = getRegion()->getCapability("ObjectMediaNavigate"); - if(cap.empty()) - { - // XXX *TODO: deal with no cap! It may happen! (retry?) - LL_WARNS("Media") << "Can't broadcast navigate event -- ObjectMediaNavigate cap is not available" << LL_ENDL; - return; - } - - // If we got here, the cap is available. Index through all faces that have this media and send the navigate message. - LLSD sd; - sd["object_id"] = mID; - sd["current_url"] = new_location; - sd["texture_index"] = face_index; - LLHTTPClient::post(cap, sd, new LLMediaDataResponder("ObjectMediaNavigate", sd, this)); + sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location); } } break; @@ -1790,29 +1913,9 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, } -void LLVOVolume::sendMediaDataUpdate() const +void LLVOVolume::sendMediaDataUpdate() { - std::string url = getRegion()->getCapability("ObjectMedia"); - if (!url.empty()) - { - LLSD sd_payload; - sd_payload["verb"] = "UPDATE"; - sd_payload[LLTextureEntry::OBJECT_ID_KEY] = mID; - LLSD object_media_data; - for (int i=0; i < getNumTEs(); i++) { - LLTextureEntry *texture_entry = getTE(i); - llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia()); - const LLSD &media_data = - (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD(); - object_media_data.append(media_data); - } - sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; - - llinfos << "Sending media data: " << getID() << " " << ll_pretty_print_sd(sd_payload) << llendl; - - LLHTTPClient::post(url, sd_payload, new LLMediaDataResponder("ObjectMedia", sd_payload, this)); - } - // XXX *TODO: deal with no cap! It may happen! (retry?) + sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this)); } void LLVOVolume::removeMediaImpl(S32 texture_index) @@ -1905,6 +2008,22 @@ viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const return NULL; } +F64 LLVOVolume::getTotalMediaInterest() const +{ + F64 interest = (F64)0.0; + int i = 0; + const int end = getNumTEs(); + for ( ; i < end; ++i) + { + const viewer_media_t &impl = getMediaImpl(i); + if (!impl.isNull()) + { + interest += impl->getInterest(); + } + } + return interest; +} + S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id) { S32 end = (S32)mMediaImplList.size() ; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 9a79b620d5..90dfa2204b 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -45,6 +45,8 @@ class LLViewerTextureAnim; class LLDrawPool; class LLSelectNode; +class LLObjectMediaDataClient; +class LLObjectMediaNavigateClient; typedef std::vector<viewer_media_t> media_list_t; @@ -231,17 +233,29 @@ public: BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); - void updateObjectMediaData(const LLSD &media_data_duples); + // Functions that deal with media, or media navigation + + // Update this object's media data with the given media data array + // (typically this is only called upon a response from a server request) + void updateObjectMediaData(const LLSD &media_data_array); + + // Bounce back media at the given index to its current URL (or home URL, if current URL is empty) + void mediaNavigateBounceBack(U8 texture_index); + + // Returns whether or not this object has permission to navigate the given media entry + bool hasNavigatePermission(const LLMediaEntry* media_entry); + void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event); // Sync the given media data with the impl and the given te void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent); // Send media data update to the simulator. - void sendMediaDataUpdate() const; + void sendMediaDataUpdate(); viewer_media_t getMediaImpl(U8 face_id) const; S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id); + F64 getTotalMediaInterest() const; bool hasMedia() const; @@ -283,6 +297,9 @@ public: static F32 sLODFactor; // LOD scale factor static F32 sDistanceFactor; // LOD distance factor + static LLPointer<LLObjectMediaDataClient> sObjectMediaClient; + static LLPointer<LLObjectMediaNavigateClient> sObjectMediaNavigateClient; + protected: static S32 sNumLODChanges; diff --git a/indra/newview/res/toolbuy.cur b/indra/newview/res/toolbuy.cur Binary files differdeleted file mode 100644 index c61cd76bef..0000000000 --- a/indra/newview/res/toolbuy.cur +++ /dev/null diff --git a/indra/newview/res/toolopen.cur b/indra/newview/res/toolopen.cur Binary files differdeleted file mode 100644 index 8408f7c7eb..0000000000 --- a/indra/newview/res/toolopen.cur +++ /dev/null diff --git a/indra/newview/res/toolsit.cur b/indra/newview/res/toolsit.cur Binary files differdeleted file mode 100644 index 60b0e773e5..0000000000 --- a/indra/newview/res/toolsit.cur +++ /dev/null diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index 87a8bd5787..4ac48c1857 100644 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -123,10 +123,6 @@ TOOLPICKOBJECT3 CURSOR "toolpickobject3.cur" ARROWCOPY CURSOR "arrowcop.cur" ARROWDRAGMULTI CURSOR "llarrowdragmulti.cur" ARROWCOPYMULTI CURSOR "arrowcopmulti.cur" -TOOLSIT CURSOR "toolsit.cur" -TOOLBUY CURSOR "toolbuy.cur" -TOOLPAY CURSOR "toolpay.cur" -TOOLOPEN CURSOR "toolopen.cur" TOOLPIPETTE CURSOR "toolpipette.cur" TOOLPLAY CURSOR "toolplay.cur" TOOLPAUSE CURSOR "toolpause.cur" @@ -138,8 +134,8 @@ TOOLMEDIAOPEN CURSOR "toolmediaopen.cur" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,0 - PRODUCTVERSION 2,0,0,0 + FILEVERSION 2,0,0,2639 + PRODUCTVERSION 2,0,0,2639 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -156,12 +152,12 @@ BEGIN BEGIN VALUE "CompanyName", "Linden Lab" VALUE "FileDescription", "Second Life" - VALUE "FileVersion", "2.0.0.0" + VALUE "FileVersion", "2.0.0.2639" VALUE "InternalName", "Second Life" - VALUE "LegalCopyright", "Copyright 2001-2008, Linden Research, Inc." + VALUE "LegalCopyright", "Copyright � 2001-2008, Linden Research, Inc." VALUE "OriginalFilename", "SecondLife.exe" VALUE "ProductName", "Second Life" - VALUE "ProductVersion", "2.0.0.0" + VALUE "ProductVersion", "2.0.0.2639" END END BLOCK "VarFileInfo" diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index f106796cd9..2c09689ec6 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -384,12 +384,12 @@ <texture name="TaskPanel_BG" file_name="taskpanel/TaskPanel_BG.png" preload="false" scale.left="4" scale.top="146" scale.right="146" scale.bottom="4" /> <texture name="TaskPanel_Tab_Unselected" file_name="taskpanel/TaskPanel_Tab_Over.png" preload="false" scale.left="5" scale.top="30" scale.right="36" scale.bottom="5" /> - <texture name="TextField_Search_Disabled" file_name="widgets/TextField_Search_Disabled.png" preload="true" scale.left="4" scale.top="18" scale.right="252" scale.bottom="4" /> - <texture name="TextField_Off" file_name="widgets/TextField_Off.png" preload="true" scale.left="4" scale.top="18" scale.right="252" scale.bottom="4" /> - <texture name="TextField_Search_Active" file_name="widgets/TextField_Search_Active.png" preload="true" scale.left="4" scale.top="18" scale.right="252" scale.bottom="4" /> - <texture name="TextField_Search_Off" file_name="widgets/TextField_Search_Off.png" preload="true" scale.left="4" scale.top="18" scale.right="252" scale.bottom="4" /> - <texture name="TextField_Disabled" file_name="widgets/TextField_Disabled.png" preload="true" scale.left="4" scale.top="18" scale.right="252" scale.bottom="4" /> - <texture name="TextField_Active" file_name="widgets/TextField_Active.png" preload="true" scale.left="4" scale.top="18" scale.right="252" scale.bottom="4" /> + <texture name="TextField_Search_Disabled" file_name="widgets/TextField_Search_Disabled.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> + <texture name="TextField_Off" file_name="widgets/TextField_Off.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> + <texture name="TextField_Search_Active" file_name="widgets/TextField_Search_Active.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> + <texture name="TextField_Search_Off" file_name="widgets/TextField_Search_Off.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> + <texture name="TextField_Disabled" file_name="widgets/TextField_Disabled.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> + <texture name="TextField_Active" file_name="widgets/TextField_Active.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" /> <texture name="Toast_CloseBtn" file_name="windows/Toast_CloseBtn.png" preload="true" /> <texture name="Toast" file_name="windows/Toast.png" preload="true" /> @@ -513,11 +513,6 @@ <texture name="toggle_button_off" file_name="toggle_button_off.png" preload="true" /> <texture name="toggle_button_selected" file_name="toggle_button_selected.png" preload="true" /> -<!--TODO: REPLACE CODE REFERENCE TO THIS ART WITH Icon_Minimize_Background above --> - <texture name="minimize_inactive.tga" preload="true" /> - <texture name="minimize.tga" preload="true" /> - <texture name="minimize_pressed.tga" preload="true" /> - <texture name="sm_rounded_corners_simple.tga" scale.left="4" scale.top="4" scale.bottom="4" scale.right="4" /> <texture name="rounded_square.tga" file_name="rounded_square.j2c" preload="true" scale.left="16" scale.top="16" scale.right="112" scale.bottom="16" /> diff --git a/indra/newview/skins/default/xui/da/floater_camera.xml b/indra/newview/skins/default/xui/da/floater_camera.xml index 0eb090d2e4..c52f7ab832 100644 --- a/indra/newview/skins/default/xui/da/floater_camera.xml +++ b/indra/newview/skins/default/xui/da/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="move floater" title=""> - <string name="rotate_tooltip"> +<floater name="camera_floater" title=""> + <floater.string name="rotate_tooltip"> Roter kamera omkring fokus - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Zoom kamera mod fokus - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> Flyt kamera op og ned, til venstre og højre - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Flyt kamera op og ned, til venstre og højre"/> + <joystick_zoom name="zoom" tool_tip="Zoom kamera mod fokus"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/da/floater_color_picker.xml b/indra/newview/skins/default/xui/da/floater_color_picker.xml index e6cc5774ed..c8e1fc813b 100644 --- a/indra/newview/skins/default/xui/da/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/da/floater_color_picker.xml @@ -26,6 +26,6 @@ Nuværende Farve: </text> <text name="(Drag below to save.)"> - (Træk ned og gem.) + (Træk ned og gem) </text> </floater> diff --git a/indra/newview/skins/default/xui/de/floater_camera.xml b/indra/newview/skins/default/xui/de/floater_camera.xml index 198b5b07f2..f44db713d8 100644 --- a/indra/newview/skins/default/xui/de/floater_camera.xml +++ b/indra/newview/skins/default/xui/de/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="move floater"> - <string name="rotate_tooltip"> +<floater name="camera_floater"> + <floater.string name="rotate_tooltip"> Kamera um Fokus drehen - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Kamera auf Fokus zoomen - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> Kamera nach oben, unten, links und rechts bewegen - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Kamera nach oben, unten, links und rechts bewegen"/> + <joystick_zoom name="zoom" tool_tip="Kamera auf Fokus zoomen"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/de/floater_color_picker.xml b/indra/newview/skins/default/xui/de/floater_color_picker.xml index f53a1135dc..fa2f616249 100644 --- a/indra/newview/skins/default/xui/de/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/de/floater_color_picker.xml @@ -27,6 +27,6 @@ </text> <text name="(Drag below to save.)"> (Nach unten ziehen, - um zu speichern.) + um zu speichern) </text> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml index 3ab5c18300..e1f8011cbe 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml @@ -55,14 +55,13 @@ width="220"> Type part of a person's name: </text> - <text_editor + <line_editor bevel_style="none" border_style="line" border.border_thickness="0" commit_on_focus_lost="false" follows="left|top|right" height="23" - layout="topleft" left_delta="0" name="Edit" top_pad="0" @@ -85,38 +84,7 @@ top="52" width="132" /> </panel> - <panel - border="true" - height="150" - label="Calling Cards" - layout="topleft" - left_delta="-1" - name="CallingCardsPanel" - top_delta="134" - width="135"> - <text - type="string" - length="1" - follows="left|top" - height="16" - layout="topleft" - left="10" - name="InstructSelectCallingCard" - top="8" - width="220"> - Select a calling card: - </text> - <inventory_panel - allow_multi_select="false" - border="true" - follows="left|top|right|bottom" - height="110" - layout="topleft" - left_delta="0" - name="InventoryPanel" - top_pad="7" - width="115" /> - </panel> + <panel border="none" height="150" @@ -188,8 +156,8 @@ <button follows="right|bottom" height="23" - label="Ok" - label_selected="Ok" + label="OK" + label_selected="OK" name="Select" top_pad="3" left="46" diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 053215f8ae..c65206d629 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2688,7 +2688,7 @@ height="18" layout="topleft" left="20" - max_length="63" + read_only="true" name="media_info" select_on_focus="true" top_delta="12" diff --git a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml index 0eb2c5e1be..4f501b65f3 100644 --- a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml +++ b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml @@ -1,24 +1,24 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
- can_minimize="false"
- height="108"
- layout="topleft"
- name="whitelist_entry"
- width="390">
-
- <text type="string" length="1" bottom="20" follows="top|left" height="15" layout="topleft"
- left="10" name="media_label" top="20">
- Enter a URL or URL pattern to add to the list of allowed domains
- </text>
-
- <line_editor bottom_delta="40" enabled="true" follows="left|top" font="SansSerif"
- height="20" left="10" name="whitelist_entry"
- tool_tip="Enter a URL or URL pattern to White List"
- width="350" />
-
- <button follows="top|left" height="20" font="SansSerifSmall" label="OK"
- layout="topleft" left="10" name="ok_btn" bottom_delta="28" width="64" />
-
- <button follows="top|left" height="20" font="SansSerifSmall" label="Cancel"
- layout="topleft" left_pad="5" name="cancel_btn" bottom_delta="0" width="64" />
-</floater>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_minimize="false" + height="108" + layout="topleft" + name="whitelist_entry" + width="390"> + + <text type="string" length="1" bottom="20" follows="top|left" height="15" layout="topleft" + left="10" name="media_label" top="20"> + Enter a URL or URL pattern to add to the list of allowed domains + </text> + + <line_editor bottom_delta="40" enabled="true" follows="left|top" font="SansSerif" + height="20" left="10" name="whitelist_entry" + tool_tip="Enter a URL or URL pattern to White List" + width="350" /> + + <button follows="top|left" height="20" font="SansSerifSmall" label="OK" + layout="topleft" left="10" name="ok_btn" bottom_delta="28" width="64" /> + + <button follows="top|left" height="20" font="SansSerifSmall" label="Cancel" + layout="topleft" left_pad="5" name="cancel_btn" bottom_delta="0" width="64" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml index b44acebbcf..1af07c35be 100644 --- a/indra/newview/skins/default/xui/en/inspect_avatar.xml +++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml @@ -5,16 +5,16 @@ --> <floater bevel_style="in" - bg_alpha_color="PanelDefaultBackgroundColor" + bg_opaque_color="MouseGray" can_close="false" can_minimize="false" - height="190" + height="138" layout="topleft" name="inspect_avatar" single_instance="true" sound_flags="0" visible="true" - width="300"> + width="245"> <!-- Allowed fields include: [BORN_ON] ("12/3/2008") [SL_PROFILE] (Second Life profile), @@ -36,107 +36,116 @@ Partner: [PARTNER] </string> <text - follows="left|top|right|bottom" - font="SansSerifHugeBold" - height="70" - left="10" + follows="all" + font="SansSerifLargeBold" + height="18" + left="8" name="user_name" + top="5" text_color="white" - top="20" use_ellipses="true" - value="Test Name" - width="280" - word_wrap="true" /> - <text - follows="left|top|right|bottom" - font="SansSerifBig" - height="20" - left="10" - name="user_subtitle" - text_color="white" - top="45" - width="150" /> + value="Grumpity ProductEngine" + width="240" + word_wrap="false" /> <!-- Leave text fields blank so it doesn't flash when data arrives off the network --> <text - follows="left|top|right|bottom" - height="20" - left="10" + follows="all" + height="16" + left="8" + value="Grumpity ProductEngine moose moose" name="user_details" - text_color="white" - top="85" - width="290" - word_wrap="true" /> + top_pad="0" + width="170" + use_ellipses="true" + word_wrap="false" /> <text - follows="left|top|right|bottom" - height="20" - left="10" + follows="all" + font="SansSerifSmallBold" + text_color="White" + height="18" + left="8" + name="user_subtitle" + use_ellipses="true" + top_pad="0" + width="170" /> + <text + follows="all" + height="16" + left="8" name="user_partner" - text_color="white" - top="105" - width="290" - word_wrap="true" /> - <avatar_icon - follows="left|top|right|bottom" - height="60" - left="230" - mouse_opaque="true" - name="avatar_icon" - top="15" - width="60" /> + top_pad="8" + width="240" + use_ellipses="true" + word_wrap="false" /> <slider follows="top|left" - height="30" + height="23" increment="0.05" - left="20" + left="1" max_val="0.95" min_val="0.05" name="volume_slider" show_text="false" tool_tip="Voice Volume" - top="125" + top_pad="0" value="0.5" - width="240" /> + width="150" /> <button - follows="left|top|right|bottom" + follows="all" height="16" - image_disabled="icn_speaker_dark.tga" - image_disabled_selected="icn_speaker-muted_dark.tga" - image_hover_selected="icn_speaker-muted_dark.tga" - image_selected="icn_speaker-muted_dark.tga" - image_unselected="icn_speaker_dark.tga" + image_disabled="Inv_Sound" + image_disabled_selected="Inv_Sound" + image_hover_selected="Inv_Sound" + image_selected="Inv_Sound" + image_unselected="Inv_Sound" is_toggle="true" - left="265" + left_pad="0" + top_delta="4" name="mute_btn" picture_style="true" - top="132" - width="32" /> + width="16" /> + <avatar_icon + follows="all" + height="38" + right="-25" + bevel_style="in" + border_style="line" + mouse_opaque="true" + name="avatar_icon" + top="24" + width="38" /> <button follows="top|left" - font="SansSerif" - height="20" + height="18" + image_disabled="ForwardArrow_Disabled" + image_selected="ForwardArrow_Press" + image_unselected="ForwardArrow_Off" + layout="topleft" + name="view_profile_btn" + picture_style="true" + right="-8" + top="35" + left_delta="110" + tab_stop="false" + width="18" /> + <button + follows="bottom|left" + height="23" label="Add Friend" - left="10" + left="8" + top="246" name="add_friend_btn" - top_pad="10" - width="105" /> - <button - follows="top|left" - font="SansSerif" - height="20" - label="View Profile" - left_delta="110" - name="view_profile_btn" - top_delta="0" - width="105" /> + width="100" /> <menu_button follows="top|left" - height="20" - image_overlay="windows\Icon_Gear_Foreground.png" - image_overlay_alignment="center" + height="18" + image_disabled="OptionsMenu_Disabled" + image_selected="OptionsMenu_Press" + image_unselected="OptionsMenu_Off" menu_filename="menu_inspect_avatar_gear.xml" name="gear_btn" picture_style="true" - top_delta="0" - left_delta="110" - width="60"/> + right="-10" + top="249" + width="18" /> </floater> diff --git a/indra/newview/skins/default/xui/en/inspect_object.xml b/indra/newview/skins/default/xui/en/inspect_object.xml index cc56f630b0..97df28aa30 100644 --- a/indra/newview/skins/default/xui/en/inspect_object.xml +++ b/indra/newview/skins/default/xui/en/inspect_object.xml @@ -17,8 +17,8 @@ width="300"> <string name="Creator">By [CREATOR]</string> <string name="CreatorAndOwner"> -By [CREATOR] -Owned by [OWNER] +by [CREATOR] +owner [OWNER] </string> <!-- *TODO: Might need to change to [AMOUNT] if icon contains "L$" --> <string name="Price">L$[AMOUNT]</string> @@ -28,57 +28,59 @@ Owned by [OWNER] <text follows="all" font="SansSerifLargeBold" - height="20" + height="16" left="8" name="object_name" - text_color="white" - top="8" + text_color="White" + top="5" use_ellipses="true" value="Test Object Name That Is Really Long" - width="268" /> + width="291" /> <text follows="all" font="SansSerif" height="30" - left="10" + left="8" name="object_creator" top_pad="0" - width="280"> -By Longavatarname Johnsonlongstonnammer -Owned by James Linden - </text> - <text - follows="all" - height="45" - left="100" - name="object_description" - top_pad="4" - width="200" - word_wrap="true"> -This is a really long description for an object being as how it is at least 80 characters in length and maybe more like 120 at this point. Who knows, really? + use_ellipses="true" + width="275"> +by Longavatarname Johnsonlongstonnammer +owner James Linden </text> <!-- *TODO: Replace this icon --> <icon name="price_icon" - image_name="Favorite_Star_Active" - left="5" + image_name="Icon_For_Sale" + left="7" width="16" height="16" - top="79" + top="52" follows="left|top" /> <text follows="all" font="SansSerifSmallBold" - height="45" - left="22" + height="16" + left_pad="5" name="price_text" text_color="white" - top="80" + top="54" font_shadow="none" - width="80"> + width="150"> L$300,000 </text> + <text + follows="all" + height="30" + left="8" + name="object_description" + top_pad="0" + width="291" + use_ellipses="true" + word_wrap="true"> +This is a really long description for an object being as how it is at least 80 characters in length and maybe more like 120 at this point. Who knows, really? + </text> <!-- Overlapping buttons for all default actions. Show "Buy" if for sale, "Sit" if can sit, etc. --> <button @@ -88,7 +90,7 @@ L$300,000 label="Buy" left="10" name="buy_btn" - top="116" + top="114" width="100" /> <button follows="top|left" @@ -136,27 +138,30 @@ L$300,000 top_delta="0" width="100" /> <!-- non-overlapping buttons here --> - <menu_button + <menu_button follows="top|left" - height="23" - image_overlay="Icon_Gear_Foreground" - image_overlay_alignment="center" - right="-8" - menu_filename="menu_inspect_object_gear.xml" + height="18" + image_disabled="OptionsMenu_Disabled" + image_selected="OptionsMenu_Press" + image_unselected="OptionsMenu_Off" + menu_filename="menu_inspect_avatar_gear.xml" name="gear_btn" picture_style="true" - top_delta="0" - width="30" /> - <button + right="-10" + top_delta="5" + width="18" /> + <button follows="top|left" - height="22" - image_overlay="TabIcon_Close_Off" + height="18" + image_disabled="ForwardArrow_Disabled" + image_selected="ForwardArrow_Press" + image_unselected="ForwardArrow_Off" layout="topleft" name="more_info_btn" picture_style="true" - right="-8" - top="7" + right="-5" + top="20" left_delta="110" tab_stop="false" - width="20" /> + width="18" /> </floater> diff --git a/indra/newview/skins/default/xui/en/language_settings.xml b/indra/newview/skins/default/xui/en/language_settings.xml index 71418d446a..c523185034 100644 --- a/indra/newview/skins/default/xui/en/language_settings.xml +++ b/indra/newview/skins/default/xui/en/language_settings.xml @@ -6,7 +6,13 @@ <string name="MicrosoftLocale">english</string> <string name="DarwinLocale">C</string> <string name="LinuxLocale">C</string> - + + <!-- Note: for plural nouns, see strings.xml. For example: + AgeYearsA = singular, + AgeYearsB = plural, + AgeYearsC = plural for non-English languages like Russian + For example, LLTrans::getCountString("AgeYears", 3) is plural form B + in English and form C in Russian --> <!-- datetimeToCodes["wkday"] = "%a"; // Thu datetimeToCodes["weekday"] = "%A"; // Thursday diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 2c77f61da6..b0839ce255 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -361,18 +361,6 @@ </menu_item_call> </menu> <menu_item_check - label="Search" - layout="topleft" - name="Search" - shortcut="control|F"> - <menu_item_check.on_check - function="Floater.Visible" - parameter="search" /> - <menu_item_check.on_click - function="Floater.Toggle" - parameter="search" /> - </menu_item_check> - <menu_item_check label="World Map" layout="topleft" name="World Map" @@ -1072,6 +1060,18 @@ name="Shortcuts" tear_off="true" visible="false"> + <menu_item_check + label="Search" + layout="topleft" + name="Search" + shortcut="control|F"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="search" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="search" /> + </menu_item_check> <menu_item_call enabled="false" label="Release Keys" @@ -2503,7 +2503,6 @@ tear_off="true"> <menu_item_check label="Axes" - layout="topleft" name="Axes"> <menu_item_check.on_check function="CheckControl" @@ -2514,7 +2513,6 @@ </menu_item_check> <menu_item_check label="Tangent Basis" - layout="topleft" name="Tangent Basis"> <menu_item_check.on_check function="CheckControl" @@ -2525,7 +2523,6 @@ </menu_item_check> <menu_item_call label="Selected Texture Info Basis" - layout="topleft" name="Selected Texture Info Basis" shortcut="control|alt|shift|T"> <menu_item_call.on_click @@ -2533,7 +2530,6 @@ </menu_item_call> <menu_item_check label="Wireframe" - layout="topleft" name="Wireframe" shortcut="control|shift|R"> <menu_item_check.on_check @@ -2544,7 +2540,6 @@ </menu_item_check> <menu_item_check label="Object-Object Occlusion" - layout="topleft" name="Object-Object Occlusion" shortcut="control|shift|O"> <menu_item_check.on_check @@ -2558,7 +2553,6 @@ </menu_item_check> <menu_item_check label="Framebuffer Objects" - layout="topleft" name="Framebuffer Objects"> <menu_item_check.on_check function="CheckControl" @@ -2571,7 +2565,6 @@ </menu_item_check> <menu_item_check label="Deferred Rendering" - layout="topleft" name="Deferred Rendering"> <menu_item_check.on_check function="CheckControl" @@ -2584,7 +2577,6 @@ </menu_item_check> <menu_item_check label="Global Illumintation" - layout="topleft" name="Global Illumination"> <menu_item_check.on_check function="CheckControl" @@ -2595,10 +2587,11 @@ <menu_item_check.on_enable function="Advanced.EnableRenderDeferredGI" /> </menu_item_check> - + + <menu_item_separator /> + <menu_item_check label="Debug GL" - layout="topleft" name="Debug GL"> <menu_item_check.on_check function="CheckControl" @@ -2609,7 +2602,6 @@ </menu_item_check> <menu_item_check label="Debug Pipeline" - layout="topleft" name="Debug Pipeline"> <menu_item_check.on_check function="CheckControl" @@ -2620,7 +2612,6 @@ </menu_item_check> <menu_item_check label="Fast Alpha" - layout="topleft" name="Fast Alpha"> <menu_item_check.on_check function="CheckControl" @@ -2631,7 +2622,6 @@ </menu_item_check> <menu_item_check label="Animation Textures" - layout="topleft" name="Animation Textures"> <menu_item_check.on_check function="CheckControl" @@ -2642,7 +2632,6 @@ </menu_item_check> <menu_item_check label="Disable Textures" - layout="topleft" name="Disable Textures"> <menu_item_check.on_check function="Advanced.CheckDisableTextures" @@ -2652,7 +2641,6 @@ </menu_item_check> <menu_item_check label="Texture Atlas" - layout="topleft" name="Texture Atlas"> <menu_item_check.on_check function="Advanced.CheckTextureAtlas" @@ -2662,7 +2650,6 @@ </menu_item_check> <menu_item_check label="Render Attached Lights" - layout="topleft" name="Render Attached Lights"> <menu_item_check.on_check function="CheckControl" @@ -2673,7 +2660,6 @@ </menu_item_check> <menu_item_check label="Render Attached Particles" - layout="topleft" name="Render Attached Particles"> <menu_item_check.on_check function="CheckControl" @@ -2682,6 +2668,16 @@ function="Advanced.HandleAttchedLightParticles" parameter="RenderAttachedParticles" /> </menu_item_check> + <menu_item_check + label="Hover Highlight Objects" + name="Hover Highlight Objects"> + <menu_item_check.on_check + function="CheckControl" + parameter="RenderHighlightEnable" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RenderHighlightEnable" /> + </menu_item_check> </menu> <menu create_jump_keys="true" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 829c2e02d8..f141a909a8 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -761,7 +761,7 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now? name="url" openexternally = "1"> - http://join/secondlife.com/ + http://join.secondlife.com/ </url> <usetemplate name="okcancelbuttons" diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml index 1e7ca7aa3f..f1e2560356 100644 --- a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml +++ b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml @@ -64,7 +64,7 @@ <web_browser border_visible="false" - bottom_delta="-120" + bottom_delta="-133" follows="top|left" left="120" name="preview_media" @@ -83,7 +83,7 @@ </text> <text - bottom_delta="-20" + bottom_delta="-5" follows="top|left" height="15" left="10" @@ -161,39 +161,92 @@ radio_style="false" width="150" /> - <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Use Default Alternative Image" left="10" mouse_opaque="true" - name="alt_image_enable" radio_style="false" width="150" /> + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Use Default Alternative Image" + left="10" + mouse_opaque="true" + name="alt_image_enable" + radio_style="false" + width="150" /> - <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Auto Play Media" left="10" mouse_opaque="true" - name="auto_play" radio_style="false" width="150" /> - <text bottom_delta="-14" follows="top|left" height="15" left="30" width="340" - enabled="false" name=""> + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Auto Play Media" + left="10" + mouse_opaque="true" + name="auto_play" + radio_style="false" + width="150" /> + + <text + bottom_delta="-14" + follows="top|left" + height="15" + left="30" + width="340" + enabled="false" + name="meida_setting_note"> Note: Residents can override this setting </text> - <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Auto Scale Media on Face of Object" left="10" mouse_opaque="true" - name="auto_scale" radio_style="false" width="150" /> - <text bottom_delta="-20" follows="top|left" height="15" left="30" name=""> + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Auto Scale Media on Face of Object" + left="10" + mouse_opaque="true" + name="auto_scale" + radio_style="false" + width="150" /> + + <text + bottom_delta="-20" + follows="top|left" + height="15" + left="30" + name=""> Size: </text> - <spinner bottom_delta="0" - decimal_digits="0" enabled="true" follows="left|top" height="16" - increment="1" initial_val="256" label="" label_width="0" - left_delta="40" max_val="2000" min_val="0" mouse_opaque="true" - name="width_pixels" width="50" /> + + <spinner + bottom_delta="0" + decimal_digits="0" + enabled="true" + follows="left|top" + height="16" + increment="1" + initial_val="256" + label="" + label_width="0" + left_delta="40" + max_val="2048" + min_val="0" + mouse_opaque="true" + name="width_pixels" + width="50" /> + <text bottom_delta="0" follows="top|left" height="15" left_delta="60" name=""> X </text> <spinner bottom_delta="0" decimal_digits="0" enabled="true" follows="left|top" height="16" increment="1" initial_val="256" label="" label_width="0" - left_delta="20" max_val="2000" min_val="0" mouse_opaque="true" + left_delta="20" max_val="2048" min_val="0" mouse_opaque="true" name="height_pixels" width="50" /> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml index f11364874a..0cc1406d62 100644 --- a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml +++ b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml @@ -1,49 +1,137 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel border="true" enabled="true" follows="left|top|right|bottom" - height="500" label="Controls" left="102" mouse_opaque="true" - name="Media settings for controls" width="365"> +<panel + border="true" + enabled="true" + follows="left|top|right|bottom" + height="500" + label="Controls" + left="102" + mouse_opaque="true" + name="Media settings for controls" + width="365"> - <text bottom_delta="-50" follows="top|left" height="15" left="10" name="" enabled="false"> + <text + bottom_delta="-50" + follows="top|left" + height="15" + left="10" + name="media_perms_label_owner" + enabled="false"> Owner </text> - <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Disable Navigation & Interactivity" left="30" mouse_opaque="true" - name="perms_owner_interact" radio_style="false" width="250" /> + + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Disable Navigation & Interactivity" + left="30" + mouse_opaque="true" + name="perms_owner_interact" + radio_style="false" + width="250" /> - <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Hide Control Bar" left="30" mouse_opaque="true" - name="perms_owner_control" radio_style="false" width="250" /> + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Hide Control Bar" + left="30" + mouse_opaque="true" + name="perms_owner_control" + radio_style="false" + width="250" /> - <text bottom_delta="-36" follows="top|left" height="15" left="10" name="perms_group_name_label" enabled="false"> + <text + bottom_delta="-36" + follows="top|left" + height="15" + left="10" + name="media_perms_label_group" + enabled="false"> Group </text> - <name_box bottom_delta="-5" enabled="false" follows="left|top" font="SansSerif" - height="20" left="60" name="perms_group_name" - value ="" - width="200" /> - <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Disable Navigation & Interactivity" left="30" mouse_opaque="true" - name="perms_group_interact" radio_style="false" width="250" /> + + <name_box + bottom_delta="-5" + enabled="false" + follows="left|top" + font="SansSerif" + height="20" left="60" + name="perms_group_name" + value ="" + width="200" /> + + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Disable Navigation & Interactivity" + left="30" + mouse_opaque="true" + name="perms_group_interact" + radio_style="false" + width="250" /> - <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Hide Control Bar" left="30" mouse_opaque="true" - name="perms_group_control" radio_style="false" width="250" /> + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Hide Control Bar" + left="30" + mouse_opaque="true" + name="perms_group_control" + radio_style="false" + width="250" /> - <text bottom_delta="-36" follows="top|left" height="15" left="10" name="" enabled="false"> + <text + bottom_delta="-36" + follows="top|left" + height="15" + left="10" + name="media_perms_label_anyone" + enabled="false"> Anyone </text> - <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Disable Navigation & Interactivity" left="30" mouse_opaque="true" - name="perms_anyone_interact" radio_style="false" width="250" /> + + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Disable Navigation & Interactivity" + left="30" + mouse_opaque="true" + name="perms_anyone_interact" + radio_style="false" + width="250" /> - <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Hide Control Bar" left="30" mouse_opaque="true" - name="perms_anyone_control" radio_style="false" width="250" /> + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Hide Control Bar" + left="30" + mouse_opaque="true" + name="perms_anyone_control" + radio_style="false" + width="250" /> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml index 8b9fe2cf77..696e0b3c33 100644 --- a/indra/newview/skins/default/xui/en/panel_places.xml +++ b/indra/newview/skins/default/xui/en/panel_places.xml @@ -60,7 +60,7 @@ left="5" name="teleport_btn" top="0" - width="90" /> + width="70" /> <button follows="bottom|left" font="SansSerifSmallBold" @@ -70,7 +70,7 @@ left_pad="5" name="map_btn" top="0" - width="80" /> + width="50" /> <button enabled="false" follows="bottom|left" @@ -83,40 +83,54 @@ top="0" width="60" /> <button + follows="bottom|left" + font="SansSerifSmallBold" + height="25" + label="Edit" + layout="topleft" + left_pad="5" + name="edit_btn" + top="0" + width="50" /> + <button follows="bottom|right" font="SansSerifSmallBold" height="25" label="▼" layout="topleft" - left_pad="5" name="overflow_btn" + right="-10" top="0" width="30" /> <button - follows="bottom|left" + follows="bottom|right" font="SansSerifSmallBold" height="25" - image_disabled="widgets/SegmentedBtn_Left_Disabled.png" - image_selected="widgets/SegmentedBtn_Left_Selected.png" - image_unselected="widgets/SegmentedBtn_Left_Off.png" - label="Create" + label="Close" layout="topleft" - left="5" - name="create_landmark_btn" + name="close_btn" + right="-10" top="0" - width="70" /> + width="60" /> <button - follows="bottom|left" + follows="bottom|right" font="SansSerifSmallBold" height="25" - image_disabled="widgets/ComboButton_Disabled.png" - image_selected="widgets/ComboButton_Selected.png" - image_unselected="widgets/ComboButton_Off.png" - label="▼" + label="Cancel" + layout="topleft" + name="cancel_btn" + right="-10" + top="0" + width="60" /> + <button + follows="bottom|right" + font="SansSerifSmallBold" + height="25" + label="Save" layout="topleft" - left_pad="0" - name="folder_menu_btn" + name="save_btn" + right="-75" top="0" - width="20" /> + width="60" /> </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml b/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml index 3b1b049ff2..9845a9eb78 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml @@ -4,7 +4,7 @@ bottom="0" follows="left|top|right" height="30" - width="305" + width="333" layout="topleft" left="0" name="sidetray_tab_panel"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 3a5347fe12..d124a4cdfa 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -44,23 +44,12 @@ <!-- Tooltip, lltooltipview.cpp --> - <!-- *TODO: Most of these are now unused, eliminate them --> <string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar --> <string name="TooltipNoName">(no name)</string> <!-- No name on an object --> <string name="TooltipOwner">Owner:</string> <!-- Owner name follows --> <string name="TooltipPublic">Public</string> <!-- Public permissions on an object --> <string name="TooltipIsGroup">(Group)</string> <!-- The name before this text is that of a group --> - <string name="TooltipFlagScript">Script</string> - <string name="TooltipFlagPhysics">Physics</string> - <string name="TooltipFlagTouch">Touch</string> - <string name="TooltipFlagL$">L$</string> - <string name="TooltipFlagDropInventory">Drop Inventory</string> - <string name="TooltipFlagPhantom">Phantom</string> - <string name="TooltipFlagTemporary">Temporary</string> - <string name="TooltipFlagRightClickMenu">(Right-click for menu)</string> - <string name="TooltipFreeToCopy">Free to copy</string> <string name="TooltipForSaleL$">For Sale: L$[AMOUNT]</string> <!-- L$ version --> - <string name="TooltipForSaleMsg">For Sale: [MESSAGE]</string> <!-- Message (RetrievingData) --> <string name="TooltipFlagGroupBuild">Group Build</string> <string name="TooltipFlagNoBuild">No Build</string> <string name="TooltipFlagNoEdit">Group Build</string> @@ -1940,16 +1929,23 @@ this texture in your inventory <string name="DaysOld">[AGEDAYS] old</string> <string name="TodayOld">Joined today</string> - <!-- AgeYearsA = singular, AgeYearsB = plural, see logic in - LLTrans::getCountString() --> + <!-- AgeYearsA = singular, + AgeYearsB = plural, + AgeYearsC = plural for non-English languages like Russian + For example, LLTrans::getCountString("AgeYears", 3) is plural form B + in English and form C in Russian --> <string name="AgeYearsA">[COUNT] year</string> <string name="AgeYearsB">[COUNT] years</string> + <string name="AgeYearsC">[COUNT] years</string> <string name="AgeMonthsA">[COUNT] month</string> <string name="AgeMonthsB">[COUNT] months</string> + <string name="AgeMonthsC">[COUNT] months</string> <string name="AgeWeeksA">[COUNT] week</string> <string name="AgeWeeksB">[COUNT] weeks</string> + <string name="AgeWeeksC">[COUNT] weeks</string> <string name="AgeDaysA">[COUNT] day</string> <string name="AgeDaysB">[COUNT] days</string> + <string name="AgeDaysC">[COUNT] days</string> <!-- Account types, see LLAvatarPropertiesProcessor --> <string name="AcctTypeResident">Resident</string> @@ -2177,6 +2173,9 @@ Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh <string name="'">'</string> <string name="---">---</string> + <!-- media --> + <string name="Multiple Media">Multiple Media</string> + <!-- OSMessageBox messages --> <string name="MBCmdLineError"> An error was found parsing the command line. @@ -2246,225 +2245,585 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. </string> <!-- Avatar Shape Information --> - <string name="Attached Earlobes">Attached Earlobes</string> - <string name="Arm Length">Arm Length</string> - <string name="Back Bangs Down">Back Bangs Down</string> - <string name="Back Bangs Up">Back Bangs Up</string> - <string name="Back Hair Down">Back Hair Down</string> - <string name="Back Hair Up">Back Hair Up</string> - <string name="Belly Size">Belly Size</string> - <string name="Blonde Hair">Blonde Hair</string> - <string name="Big Eyeball">Big Eyeball</string> - <string name="Big Hair Back">Big Hair: Back</string> - <string name="Big Hair Front">Big Hair: Front</string> - <string name="Big Hair Top">Big Hair: Top</string> - <string name="Body Fat">Body Fat</string> - <string name="Body Thickness">Body Thickness</string> - <string name="Breast Buoyancy">Breast Buoyancy</string> - <string name="Breast Cleavage">Breast Cleavage</string> - <string name="Breast Size">Breast Size</string> - <string name="Bridge Width">Bridge Width</string> - <string name="Brow Size">Brow Size</string> - <string name="Butt Size">Butt Size</string> - <string name="Cheek Bones">Cheek Bones</string> - <string name="Chest Size">Chest Size</string> - <string name="Chin Angle">Chin Angle</string> - <string name="Chin Cleft">Chin Cleft</string> - <string name="Chin Depth">Chin Depth</string> - <string name="Chin-Neck">Chin-Neck</string> - <string name="Collar Back">Collar Back</string> - <string name="Collar Front">Collar Front</string> - <string name="Crooked Nose">Crooked Nose</string> - <string name="Cuff Flare">Cuff Flare</string> - <string name="Ear Angle">Ear Angle</string> - <string name="Ear Size">Ear Size</string> - <string name="Ear Tips">Ear Tips</string> - <string name="Egg Head">Egg Head</string> - <string name="Eye Bags">Eye Bags</string> - <string name="Eye Color">Eye Color</string> - <string name="Eye Depth">Eye Depth</string> - <string name="Eye Lightness">Eye Lightness</string> - <string name="Eye Opening">Eye Opening</string> - <string name="Eye Pop">Eye Pop</string> - <string name="Eye Size">Eye Size</string> - <string name="Eye Spacing">Eye Spacing</string> - <string name="Eyeball Size">Eyeball Size</string> - <string name="Eyebrow Arc">Eyebrow Arc</string> - <string name="Eyebrow Height">Eyebrow Height</string> - <string name="Eyebrow Points">Eyebrow Points</string> - <string name="Eyelash Length">Eyelash Length</string> - <string name="Eyeliner">Eyeliner</string> - <string name="Eyeliner Color">Eyeliner Color</string> - <string name="Face Shear">Face Shear</string> - <string name="Facial Definitionr">Facial Definition</string> - <string name="Fat Head">Fat Head</string> - <string name="Fat Lower Lip">Fat Lower Lip</string> - <string name="Fat Torso">Fat Torso</string> - <string name="Fat Upper Lip">Fat Upper Lip</string> - <string name="Foot Size">Foot Size</string> - <string name="Freckles">Freckles</string> - <string name="Front Bangs Down">Front Bangs Down</string> - <string name="Front Bangs Up">Front Bangs Up</string> - <string name="Front Hair Down">Front Hair Down</string> - <string name="Front Hair Up">Front Hair Up</string> - <string name="Forehead Angle">Forehead Angle</string> - <string name="Full Hair Sides">Full Hair Sides</string> - <string name="Glove Fingers">Glove Fingers</string> - <string name="Glove Length">Glove Length</string> - <string name="Hair Thickess">Hair Thickess</string> - <string name="Hair Tilted Left">Hair Tilted Left</string> - <string name="Hair Tilted Right">Hair Tilted Right</string> - <string name="Hair Volume">Hair: Volume</string> - <string name="Hand Size">Hand Size</string> - <string name="Head Length">Head Length</string> - <string name="Head Shape">Head Shape</string> - <string name="Head Size">Head Size</string> - <string name="Head Stretch">Head Stretch</string> - <string name="Heel Height">Heel Height</string> - <string name="Heel Shape">Heel Shape</string> - <string name="Height">Height</string> - <string name="Hip Width">Hip Width</string> - <string name="Hip Length">Hip Length</string> - <string name="Inner Eye Corner">Inner Eye Corner</string> - <string name="Jacket Length">Jacket Length</string> - <string name="Jacket Wrinkles">Jacket Wrinkles</string> - <string name="Jowls">Jowls</string> - <string name="Jaw Angle">Jaw Angle</string> - <string name="Jaw Jut">Jaw Jut</string> - <string name="Jaw Shape">Jaw Shape</string> - <string name="Knee Angle">Knee Angle</string> - <string name="Left Part">Left Part</string> - <string name="Leg Muscles">Leg Muscles</string> - <string name="Leg Length">Leg Length</string> - <string name="Lip Cleft">Lip Cleft</string> - <string name="Lip Cleft Depth">Lip Cleft Depth</string> - <string name="Lip Fullness">Lip Fullness</string> - <string name="Lip Pinkness">Lip Pinkness</string> - <string name="Lip Ratio">Lip Ratio</string> - <string name="Lip Thickness">Lip Thickness</string> - <string name="Lip Width">Lip Width</string> - <string name="Longcuffs">Longcuffs</string> - <string name="Love Handles">Love Handles</string> - <string name="Lower Bridge">Lower Bridge</string> - <string name="Lower Cheeks">Lower Cheeks</string> - <string name="Middle Part">Middle Part</string> - <string name="Mouth Corner">Mouth Corner</string> - <string name="Mouth Position">Mouth Position</string> - <string name="Nail Polish">Nail Polish</string> - <string name="Nail Polish Color">Nail Polish Color</string> - <string name="Neck Length">Neck Length</string> - <string name="Neck Thickness">Neck Thickness</string> - <string name="Nose Size">Nose Size</string> - <string name="Nose Thickness">Nose Thickness</string> - <string name="Nose Tip Angle">Nose Tip Angle</string> - <string name="Nose Tip Shape">Nose Tip Shape</string> - <string name="Nose Width">Nose Width</string> - <string name="Nostril Division">Nostril Division</string> - <string name="Nostril Width">Nostril Width</string> - <string name="Open Front">Open Front</string> - <string name="Lipstick Color">Lipstick Color</string> - <string name="Lipstick">Lipstick</string> - <string name="Lipgloss">Lipgloss</string> - <string name="Blush">Blush</string> - <string name="Blush Color">Blush Color</string> - <string name="Blush Opacity">Blush Opacity</string> - <string name="Inner Shadow">Inner Shadow</string> - <string name="In Shdw Color">Inner Shadow Color</string> - <string name="In Shdw Opacity">Inner Shadow Opacity</string> - <string name="Body Definition">Body Definition</string> - <string name="Body Freckles">Body Freckles</string> - <string name="Facial Definition">Facial Definition</string> - <string name="Hair Front">Hair: Front</string> - <string name="Hair Sides">Hair: Sides</string> - <string name="Hair Back">Hair: Back</string> - <string name="Front Fringe">Front Fringe</string> - <string name="Side Fringe">Side Fringe</string> - <string name="Back Fringe">Back Fringe</string> - <string name="Hair Sweep">Hair Sweep</string> - <string name="Pigtails">Pigtails</string> - <string name="Ponytail">Ponytail</string> - <string name="Hair Tilt">Hair Tilt</string> - <string name="Eyebrow Size">Eyebrow Size</string> - <string name="Eyebrow Density">Eyebrow Density</string> - <!-- string name="Hair Thickess">Hair Thickess</string Need a second string for Body Parts > Hair > Facial? --> - <string name="Sideburns">Sideburns</string> - <string name="Moustache">Moustache</string> - <string name="Soulpatch">Soulpatch</string> - <string name="Chin Curtains">Chin Curtains</string> - <string name="Outer Eye Corner">Outer Eye Corner</string> - <string name="Outer Shadow">Outer Shadow</string> - <string name="Out Shdw Opacity">Outer Shadow Opacity</string> - <string name="Out Shdw Color">Outer Shadow Color</string> - <string name="Package">Package</string> - <string name="Pants Crotch">Pants Crotch</string> - <string name="Pants Fit">Pants Fit</string> - <string name="Pants Length">Pants Length</string> - <string name="Pants Waist">Pants Waist</string> - <string name="Pants Wrinkles">Pants Wrinkles</string> - <string name="Part Bangs">Part Bangs</string> - <string name="Pectorals">Pectorals</string> - <string name="Platform Height">Platform Height</string> - <string name="Platform Width">Platform Width</string> - <string name="Pigment">Pigment</string> - <string name="Puffy Eyelids">Puffy Eyelids</string> - <string name="Rainbow Color">Rainbow Color</string> - <string name="Red Hair">Red Hair</string> - <string name="Right Part">Right Part</string> - <string name="Round Forehead">Round Forehead</string> - <string name="Rosy Complexion">Rosy Complexion</string> - <string name="Ruddiness">Ruddiness</string> - <string name="Rumpled Hair">Rumpled Hair</string> - <string name="Saddle Bags">Saddle Bags</string> - <string name="Scrawny Leg">Scrawny Leg</string> - <string name="Shear Back">Shear Back</string> - <string name="Shear Face">Shear Face</string> - <string name="Shear Front">Shear Front</string> - <string name="Shift Mouth">Shift Mouth</string> - <string name="Shirt Bottom">Shirt Bottom</string> - <string name="Shirt Fit">Shirt Fit</string> - <string name="Shirt Wrinkles">Shirt Wrinkles</string> - <string name="Shoe Height">Shoe Height</string> - <string name="Shoulders">Shoulders</string> - <string name="Side Bangs Down">Side Bangs Down</string> - <string name="Side Bangs Up">Side Bangs Up</string> - <string name="Sides Hair Down">Sides Hair Down</string> - <string name="Sides Hair Up">Sides Hair Up</string> - <string name="Skirt Fit">Skirt Fit</string> - <string name="Skirt Length">Skirt Length</string> - <string name="Slanted Forehead">Slanted Forehead</string> - <string name="Sleeve Length">Sleeve Length</string> - <string name="Sleeve Looseness">Sleeve Looseness</string> - <string name="Slit Back">Slit: Back</string> - <string name="Slit Front">Slit: Front</string> - <string name="Slit Left">Slit: Left</string> - <string name="Slit Right">Slit: Right</string> - <string name="Socks Length">Socks Length</string> - <string name="Spiked Hair">Spiked Hair</string> - <string name="Squash/Stretch Head">Squash/Stretch Head</string> - <string name="Swept Back Hair">Swept Back Hair</string> - <string name="Swept Forward Hair">Swept Forward Hair</string> - <string name="Taper Back">Taper Back</string> - <string name="Taper Front">Taper Front</string> - <string name="Toe Shape">Toe Shape</string> - <string name="Toe Thickness">Toe Thickness</string> - <string name="Toe Length">Toe Length</string> - <string name="Torso Length">Torso Length</string> - <string name="Torso Muscles">Torso Muscles</string> - <string name="Torso Scrawny">Torso Scrawny</string> - <string name="Upper Bridge">Upper Bridge</string> - <string name="Upper Cheeks">Upper Cheeks</string> - <string name="Upper Chin Cleft">Upper Chin Cleft</string> - <string name="Upper Eyelid Fold">Upper Eyelid Fold</string> - <string name="Waist Height">Waist Height</string> - <string name="White Hair">White Hair</string> - <string name="big belly skirt">big belly skirt</string> - <string name="bigbutt skirt">bigbutt skirt</string> - <string name="bustle skirt">Bustle Skirt</string> - <string name="legs skirt">legs skirt</string> - <string name="loose skirt">loose skirt</string> - <string name="poofy skirt">poofy skirt</string> - <string name="tight skirt">tight skirt</string> - <string name="wrinkles">Wrinkles</string> +<string name="5 O'Clock Shadow">5 O'Clock Shadow</string> +<string name="5 O'Clock Shadow bump">5 O'Clock Shadow bump</string> +<string name="All White">All White</string> +<string name="Anime Eyes">Anime Eyes</string> +<string name="Arced">Arced</string> +<string name="Arm Length">Arm Length</string> +<string name="Attached">Attached</string> +<string name="Attached Earlobes">Attached Earlobes</string> +<string name="BELLY">BELLY</string> +<string name="Back Bangs">Back Bangs</string> +<string name="Back Bangs Down">Back Bangs Down</string> +<string name="Back Bangs Up">Back Bangs Up</string> +<string name="Back Fringe">Back Fringe</string> +<string name="Back Hair">Back Hair</string> +<string name="Back Hair Down">Back Hair Down</string> +<string name="Back Hair Up">Back Hair Up</string> +<string name="Baggy">Baggy</string> +<string name="Bangs">Bangs</string> +<string name="Bangs Down">Bangs Down</string> +<string name="Bangs Up">Bangs Up</string> +<string name="Beady Eyes">Beady Eyes</string> +<string name="Belly Size">Belly Size</string> +<string name="Big">Big</string> +<string name="Big Butt">Big Butt</string> +<string name="Big Eyeball">Big Eyeball</string> +<string name="Big Hair Back">Big Hair Back</string> +<string name="Big Hair Front">Big Hair Front</string> +<string name="Big Hair Top">Big Hair Top</string> +<string name="Big Head">Big Head</string> +<string name="Big Pectorals">Big Pectorals</string> +<string name="Big Spikes">Big Spikes</string> +<string name="Black">Black</string> +<string name="Blonde">Blonde</string> +<string name="Blonde Hair">Blonde Hair</string> +<string name="Blush">Blush</string> +<string name="Blush Color">Blush Color</string> +<string name="Blush Opacity">Blush Opacity</string> +<string name="Body Definition">Body Definition</string> +<string name="Body Fat">Body Fat</string> +<string name="Body Freckles">Body Freckles</string> +<string name="Body Thick">Body Thick</string> +<string name="Body Thickness">Body Thickness</string> +<string name="Body Thin">Body Thin</string> +<string name="Bottom">Bottom</string> +<string name="Bottom Left">Bottom Left</string> +<string name="Bottom Right">Bottom Right</string> +<string name="Bottom bump">Bottom bump</string> +<string name="Bow Legged">Bow Legged</string> +<string name="Breast Buoyancy">Breast Buoyancy</string> +<string name="Breast Cleavage">Breast Cleavage</string> +<string name="Breast Size">Breast Size</string> +<string name="Bridge Width">Bridge Width</string> +<string name="Broad">Broad</string> +<string name="Brow Size">Brow Size</string> +<string name="Bug Eyes">Bug Eyes</string> +<string name="Bugged Eyes">Bugged Eyes</string> +<string name="Bulbous">Bulbous</string> +<string name="Bulbous Nose">Bulbous Nose</string> +<string name="Bump base">Bump base</string> +<string name="Bump upperdef">Bump upperdef</string> +<string name="Bushy Eyebrows">Bushy Eyebrows</string> +<string name="Bushy Hair">Bushy Hair</string> +<string name="Butt Size">Butt Size</string> +<string name="CHEST">CHEST</string> +<string name="Center">Center</string> +<string name="Center 2">Center 2</string> +<string name="Chaplin">Chaplin</string> +<string name="Cheek Bones">Cheek Bones</string> +<string name="Chest">Chest</string> +<string name="Chest Size">Chest Size</string> +<string name="Chin">Chin</string> +<string name="Chin Angle">Chin Angle</string> +<string name="Chin Cleft">Chin Cleft</string> +<string name="Chin Curtains">Chin Curtains</string> +<string name="Chin Curtains bump">Chin Curtains bump</string> +<string name="Chin Depth">Chin Depth</string> +<string name="Chin Heavy">Chin Heavy</string> +<string name="Chin In">Chin In</string> +<string name="Chin Out">Chin Out</string> +<string name="Chin-Neck">Chin-Neck</string> +<string name="Clear">Clear</string> +<string name="Cleft">Cleft</string> +<string name="Close Set Eyes">Close Set Eyes</string> +<string name="Closed">Closed</string> +<string name="Closed Back">Closed Back</string> +<string name="Closed Front">Closed Front</string> +<string name="Closed Left">Closed Left</string> +<string name="Closed Right">Closed Right</string> +<string name="Coin Purse">Coin Purse</string> +<string name="Collar Back">Collar Back</string> +<string name="Collar Back Height Cloth">Collar Back Height Cloth</string> +<string name="Collar Back Shadow Height">Collar Back Shadow Height</string> +<string name="Collar Back bump">Collar Back bump</string> +<string name="Collar Front">Collar Front</string> +<string name="Collar Front Height Cloth">Collar Front Height Cloth</string> +<string name="Collar Front Shadow Height">Collar Front Shadow Height</string> +<string name="Collar Front bump">Collar Front bump</string> +<string name="Corner Down">Corner Down</string> +<string name="Corner Normal">Corner Normal</string> +<string name="Corner Up">Corner Up</string> +<string name="Creased">Creased</string> +<string name="Crooked Nose">Crooked Nose</string> +<string name="Cropped Hair">Cropped Hair</string> +<string name="Cuff Flare">Cuff Flare</string> +<string name="Dark">Dark</string> +<string name="Dark Green">Dark Green</string> +<string name="Darker">Darker</string> +<string name="Deep">Deep</string> +<string name="Default Heels">Default Heels</string> +<string name="Default Toe">Default Toe</string> +<string name="Dense">Dense</string> +<string name="Dense hair">Dense hair</string> +<string name="Double Chin">Double Chin</string> +<string name="Downturned">Downturned</string> +<string name="Duffle Bag">Duffle Bag</string> +<string name="Ear Angle">Ear Angle</string> +<string name="Ear Size">Ear Size</string> +<string name="Ear Tips">Ear Tips</string> +<string name="Egg Head">Egg Head</string> +<string name="Eye Bags">Eye Bags</string> +<string name="Eye Color">Eye Color</string> +<string name="Eye Depth">Eye Depth</string> +<string name="Eye Lightness">Eye Lightness</string> +<string name="Eye Opening">Eye Opening</string> +<string name="Eye Pop">Eye Pop</string> +<string name="Eye Size">Eye Size</string> +<string name="Eye Spacing">Eye Spacing</string> +<string name="Eyeball Size">Eyeball Size</string> +<string name="Eyebrow Arc">Eyebrow Arc</string> +<string name="Eyebrow Density">Eyebrow Density</string> +<string name="Eyebrow Density Bump">Eyebrow Density Bump</string> +<string name="Eyebrow Height">Eyebrow Height</string> +<string name="Eyebrow Points">Eyebrow Points</string> +<string name="Eyebrow Size">Eyebrow Size</string> +<string name="Eyebrow Size Bump">Eyebrow Size Bump</string> +<string name="Eyelash Length">Eyelash Length</string> +<string name="Eyeliner">Eyeliner</string> +<string name="Eyeliner Color">Eyeliner Color</string> +<string name="Eyes Back">Eyes Back</string> +<string name="Eyes Bugged">Eyes Bugged</string> +<string name="Eyes Forward">Eyes Forward</string> +<string name="Eyes Long Head">Eyes Long Head</string> +<string name="Eyes Shear Left Up">Eyes Shear Left Up</string> +<string name="Eyes Shear Right Up">Eyes Shear Right Up</string> +<string name="Eyes Short Head">Eyes Short Head</string> +<string name="Eyes Spread">Eyes Spread</string> +<string name="Eyes Sunken">Eyes Sunken</string> +<string name="Eyes Together">Eyes Together</string> +<string name="Face Shear">Face Shear</string> +<string name="Facial Definition">Facial Definition</string> +<string name="Far Set Eyes">Far Set Eyes</string> +<string name="Fat">Fat</string> +<string name="Fat Head">Fat Head</string> +<string name="Fat Lips">Fat Lips</string> +<string name="Fat Lower">Fat Lower</string> +<string name="Fat Lower Lip">Fat Lower Lip</string> +<string name="Fat Torso">Fat Torso</string> +<string name="Fat Upper">Fat Upper</string> +<string name="Fat Upper Lip">Fat Upper Lip</string> +<string name="Female">Female</string> +<string name="Fingerless">Fingerless</string> +<string name="Fingers">Fingers</string> +<string name="Flared Cuffs">Flared Cuffs</string> +<string name="Flat">Flat</string> +<string name="Flat Butt">Flat Butt</string> +<string name="Flat Head">Flat Head</string> +<string name="Flat Toe">Flat Toe</string> +<string name="Foot Size">Foot Size</string> +<string name="Forehead Angle">Forehead Angle</string> +<string name="Forehead Heavy">Forehead Heavy</string> +<string name="Freckles">Freckles</string> +<string name="Front Bangs Down">Front Bangs Down</string> +<string name="Front Bangs Up">Front Bangs Up</string> +<string name="Front Fringe">Front Fringe</string> +<string name="Front Hair">Front Hair</string> +<string name="Front Hair Down">Front Hair Down</string> +<string name="Front Hair Up">Front Hair Up</string> +<string name="Full Back">Full Back</string> +<string name="Full Eyeliner">Full Eyeliner</string> +<string name="Full Front">Full Front</string> +<string name="Full Hair Sides">Full Hair Sides</string> +<string name="Full Sides">Full Sides</string> +<string name="Glossy">Glossy</string> +<string name="Glove Fingers">Glove Fingers</string> +<string name="Glove Fingers bump">Glove Fingers bump</string> +<string name="Glove Length">Glove Length</string> +<string name="Glove Length bump">Glove Length bump</string> +<string name="HEAD">HEAD</string> +<string name="Hair">Hair</string> +<string name="Hair Back">Hair Back</string> +<string name="Hair Front">Hair Front</string> +<string name="Hair Sides">Hair Sides</string> +<string name="Hair Sweep">Hair Sweep</string> +<string name="Hair Thickess">Hair Thickess</string> +<string name="Hair Thickness">Hair Thickness</string> +<string name="Hair Tilt">Hair Tilt</string> +<string name="Hair Tilted Left">Hair Tilted Left</string> +<string name="Hair Tilted Right">Hair Tilted Right</string> +<string name="Hair Volume">Hair Volume</string> +<string name="Hand Size">Hand Size</string> +<string name="Handlebars">Handlebars</string> +<string name="Head Length">Head Length</string> +<string name="Head Shape">Head Shape</string> +<string name="Head Size">Head Size</string> +<string name="Head Stretch">Head Stretch</string> +<string name="Heel Height">Heel Height</string> +<string name="Heel Shape">Heel Shape</string> +<string name="Height">Height</string> +<string name="High">High</string> +<string name="High Heels">High Heels</string> +<string name="High Jaw">High Jaw</string> +<string name="High Platforms">High Platforms</string> +<string name="High and Tight">High and Tight</string> +<string name="Higher">Higher</string> +<string name="Hip Length">Hip Length</string> +<string name="Hip Width">Hip Width</string> +<string name="In">In</string> +<string name="In Shdw Color">In Shdw Color</string> +<string name="In Shdw Opacity">In Shdw Opacity</string> +<string name="Inner Eye Corner">Inner Eye Corner</string> +<string name="Inner Eye Shadow">Inner Eye Shadow</string> +<string name="Inner Shadow">Inner Shadow</string> +<string name="Jacket Collar Back bump">Jacket Collar Back bump</string> +<string name="Jacket Collar Front bump">Jacket Collar Front bump</string> +<string name="Jacket Length">Jacket Length</string> +<string name="Jacket Sleeve Length bump">Jacket Sleeve Length bump</string> +<string name="Jacket Wrinkles">Jacket Wrinkles</string> +<string name="Jaw Angle">Jaw Angle</string> +<string name="Jaw Jut">Jaw Jut</string> +<string name="Jaw Shape">Jaw Shape</string> +<string name="Join">Join</string> +<string name="Jowls">Jowls</string> +<string name="Knee Angle">Knee Angle</string> +<string name="Knock Kneed">Knock Kneed</string> +<string name="L Forearm">L Forearm</string> +<string name="L Lower Leg">L Lower Leg</string> +<string name="L Upper Arm">L Upper Arm</string> +<string name="L Upper Leg">L Upper Leg</string> + +<string name="Large">Large</string> +<string name="Large Hands">Large Hands</string> +<string name="Left">Left</string> +<string name="Left Ear">Left Ear</string> +<string name="Left Eyeball">Left Eyeball</string> +<string name="Left Foot">Left Foot</string> +<string name="Left Hand">Left Hand</string> +<string name="Left Hip">Left Hip</string> +<string name="Left Part">Left Part</string> +<string name="Left Pec">Left Pec</string> +<string name="Left Shoulder">Left Shoulder</string> +<string name="Leg Length">Leg Length</string> +<string name="Leg Muscles">Leg Muscles</string> +<string name="Less">Less</string> +<string name="Less Body Fat">Less Body Fat</string> +<string name="Less Curtains">Less Curtains</string> +<string name="Less Freckles">Less Freckles</string> +<string name="Less Full">Less Full</string> +<string name="Less Gravity">Less Gravity</string> +<string name="Less Love">Less Love</string> +<string name="Less Muscles">Less Muscles</string> +<string name="Less Muscular">Less Muscular</string> +<string name="Less Rosy">Less Rosy</string> +<string name="Less Round">Less Round</string> +<string name="Less Saddle">Less Saddle</string> +<string name="Less Square">Less Square</string> +<string name="Less Volume">Less Volume</string> +<string name="Less soul">Less soul</string> +<string name="Light">Light</string> +<string name="Lighter">Lighter</string> +<string name="Lip Cleft">Lip Cleft</string> +<string name="Lip Cleft Depth">Lip Cleft Depth</string> +<string name="Lip Fullness">Lip Fullness</string> +<string name="Lip Pinkness">Lip Pinkness</string> +<string name="Lip Ratio">Lip Ratio</string> +<string name="Lip Thickness">Lip Thickness</string> +<string name="Lip Width">Lip Width</string> +<string name="Lipgloss">Lipgloss</string> +<string name="Lipstick">Lipstick</string> +<string name="Lipstick Color">Lipstick Color</string> +<string name="Long">Long</string> +<string name="Long Head">Long Head</string> +<string name="Long Hips">Long Hips</string> +<string name="Long Legs">Long Legs</string> +<string name="Long Neck">Long Neck</string> +<string name="Long Pigtails">Long Pigtails</string> +<string name="Long Ponytail">Long Ponytail</string> +<string name="Long Torso">Long Torso</string> +<string name="Long arms">Long arms</string> +<string name="Longcuffs">Longcuffs</string> +<string name="Loose Lower Clothing">Loose Lower Clothing</string> +<string name="Loose Pants">Loose Pants</string> +<string name="Loose Shirt">Loose Shirt</string> +<string name="Loose Sleeves">Loose Sleeves</string> +<string name="Loose Upper Clothing">Loose Upper Clothing</string> +<string name="Love Handles">Love Handles</string> +<string name="Low">Low</string> +<string name="Low Heels">Low Heels</string> +<string name="Low Jaw">Low Jaw</string> +<string name="Low Platforms">Low Platforms</string> +<string name="Low and Loose">Low and Loose</string> +<string name="Lower">Lower</string> +<string name="Lower Bridge">Lower Bridge</string> +<string name="Lower Cheeks">Lower Cheeks</string> +<string name="Lower Clothes Shading">Lower Clothes Shading</string> +<string name="Male">Male</string> +<string name="Middle Part">Middle Part</string> +<string name="More">More</string> +<string name="More Blush">More Blush</string> +<string name="More Body Fat">More Body Fat</string> +<string name="More Curtains">More Curtains</string> +<string name="More Eyeshadow">More Eyeshadow</string> +<string name="More Freckles">More Freckles</string> +<string name="More Full">More Full</string> +<string name="More Gravity">More Gravity</string> +<string name="More Lipstick">More Lipstick</string> +<string name="More Love">More Love</string> +<string name="More Lower Lip">More Lower Lip</string> +<string name="More Muscles">More Muscles</string> +<string name="More Muscular">More Muscular</string> +<string name="More Rosy">More Rosy</string> +<string name="More Round">More Round</string> +<string name="More Saddle">More Saddle</string> +<string name="More Sloped">More Sloped</string> +<string name="More Square">More Square</string> +<string name="More Upper Lip">More Upper Lip</string> +<string name="More Vertical">More Vertical</string> +<string name="More Volume">More Volume</string> +<string name="More soul">More soul</string> +<string name="Moustache">Moustache</string> +<string name="Moustache bump">Moustache bump</string> +<string name="Mouth">Mouth</string> +<string name="Mouth Corner">Mouth Corner</string> +<string name="Mouth Position">Mouth Position</string> +<string name="Mowhawk">Mowhawk</string> +<string name="Muscular">Muscular</string> +<string name="Mutton Chops">Mutton Chops</string> +<string name="NECK">NECK</string> +<string name="Nail Polish">Nail Polish</string> +<string name="Nail Polish Color">Nail Polish Color</string> +<string name="Narrow">Narrow</string> +<string name="Narrow Back">Narrow Back</string> +<string name="Narrow Front">Narrow Front</string> +<string name="Narrow Lips">Narrow Lips</string> +<string name="Natural">Natural</string> +<string name="Neck Length">Neck Length</string> +<string name="Neck Thickness">Neck Thickness</string> +<string name="No Blush">No Blush</string> +<string name="No Eyeliner">No Eyeliner</string> +<string name="No Eyeshadow">No Eyeshadow</string> +<string name="No Heels">No Heels</string> +<string name="No Lipgloss">No Lipgloss</string> +<string name="No Lipstick">No Lipstick</string> +<string name="No Part">No Part</string> +<string name="No Polish">No Polish</string> +<string name="No Red">No Red</string> +<string name="No Spikes">No Spikes</string> +<string name="No White">No White</string> +<string name="No Wrinkles">No Wrinkles</string> +<string name="None">None</string> +<string name="Normal Lower">Normal Lower</string> +<string name="Normal Upper">Normal Upper</string> +<string name="Nose">Nose</string> +<string name="Nose Left">Nose Left</string> +<string name="Nose Right">Nose Right</string> +<string name="Nose Size">Nose Size</string> +<string name="Nose Thickness">Nose Thickness</string> +<string name="Nose Tip Angle">Nose Tip Angle</string> +<string name="Nose Tip Shape">Nose Tip Shape</string> +<string name="Nose Width">Nose Width</string> +<string name="Nostril Division">Nostril Division</string> +<string name="Nostril Width">Nostril Width</string> +<string name="NotHair">NotHair</string> +<string name="Old">Old</string> +<string name="Opaque">Opaque</string> +<string name="Open">Open</string> +<string name="Open Back">Open Back</string> +<string name="Open Front">Open Front</string> +<string name="Open Left">Open Left</string> +<string name="Open Right">Open Right</string> +<string name="Orange">Orange</string> +<string name="Out">Out</string> +<string name="Out Shdw Color">Out Shdw Color</string> +<string name="Out Shdw Opacity">Out Shdw Opacity</string> +<string name="Outer Eye Corner">Outer Eye Corner</string> +<string name="Outer Eye Shadow">Outer Eye Shadow</string> +<string name="Outer Shadow">Outer Shadow</string> +<string name="Overbite">Overbite</string> +<string name="PELVIS">PELVIS</string> +<string name="Package">Package</string> +<string name="Painted Nails">Painted Nails</string> +<string name="Pale">Pale</string> +<string name="Pants Crotch">Pants Crotch</string> +<string name="Pants Fit">Pants Fit</string> +<string name="Pants Length">Pants Length</string> +<string name="Pants Length Cloth">Pants Length Cloth</string> +<string name="Pants Length Shadow">Pants Length Shadow</string> +<string name="Pants Waist">Pants Waist</string> +<string name="Pants Wrinkles">Pants Wrinkles</string> +<string name="Part">Part</string> +<string name="Part Bangs">Part Bangs</string> +<string name="Pectorals">Pectorals</string> +<string name="Pelvis">Pelvis</string> +<string name="Pigment">Pigment</string> +<string name="Pigtails">Pigtails</string> +<string name="Pink">Pink</string> +<string name="Pinker">Pinker</string> +<string name="Platform Height">Platform Height</string> +<string name="Platform Width">Platform Width</string> +<string name="Pointy">Pointy</string> +<string name="Pointy Heels">Pointy Heels</string> +<string name="Pointy Toe">Pointy Toe</string> +<string name="Ponytail">Ponytail</string> +<string name="Poofy Skirt">Poofy Skirt</string> +<string name="Pop Left Eye">Pop Left Eye</string> +<string name="Pop Right Eye">Pop Right Eye</string> +<string name="Puffy">Puffy</string> +<string name="Puffy Eyelids">Puffy Eyelids</string> +<string name="R Forearm">R Forearm</string> +<string name="R Lower Leg">R Lower Leg</string> +<string name="R Upper Arm">R Upper Arm</string> +<string name="R Upper Leg">R Upper Leg</string> +<string name="Rainbow Color">Rainbow Color</string> +<string name="Red Hair">Red Hair</string> +<string name="Red Skin">Red Skin</string> +<string name="Regular">Regular</string> +<string name="Regular Muscles">Regular Muscles</string> +<string name="Right">Right</string> +<string name="Right Ear">Right Ear</string> +<string name="Right Eyeball">Right Eyeball</string> +<string name="Right Foot">Right Foot</string> +<string name="Right Hand">Right Hand</string> +<string name="Right Hip">Right Hip</string> +<string name="Right Part">Right Part</string> +<string name="Right Pec">Right Pec</string> +<string name="Right Shoulder">Right Shoulder</string> +<string name="Rosy Complexion">Rosy Complexion</string> +<string name="Round">Round</string> +<string name="Round Forehead">Round Forehead</string> +<string name="Ruddiness">Ruddiness</string> +<string name="Ruddy">Ruddy</string> +<string name="Rumpled Hair">Rumpled Hair</string> +<string name="Saddle Bags">Saddle Bags</string> +<string name="Saddlebags">Saddlebags</string> +<string name="Scrawny">Scrawny</string> +<string name="Scrawny Leg">Scrawny Leg</string> +<string name="Separate">Separate</string> +<string name="Shading">Shading</string> +<string name="Shadow hair">Shadow hair</string> +<string name="Shallow">Shallow</string> +<string name="Shear Back">Shear Back</string> +<string name="Shear Face">Shear Face</string> +<string name="Shear Front">Shear Front</string> +<string name="Shear Left">Shear Left</string> +<string name="Shear Left Up">Shear Left Up</string> +<string name="Shear Right">Shear Right</string> +<string name="Shear Right Up">Shear Right Up</string> +<string name="Sheared Back">Sheared Back</string> +<string name="Sheared Front">Sheared Front</string> +<string name="Shift Left">Shift Left</string> +<string name="Shift Mouth">Shift Mouth</string> +<string name="Shift Right">Shift Right</string> +<string name="Shirt Bottom">Shirt Bottom</string> +<string name="Shirt Bottom Cloth">Shirt Bottom Cloth</string> +<string name="Shirt Fit">Shirt Fit</string> +<string name="Shirt Shadow Bottom">Shirt Shadow Bottom</string> +<string name="Shirt Wrinkles">Shirt Wrinkles</string> +<string name="Shoe Height">Shoe Height</string> +<string name="Shoe Height bump">Shoe Height bump</string> +<string name="Short">Short</string> +<string name="Short Arms">Short Arms</string> +<string name="Short Legs">Short Legs</string> +<string name="Short Neck">Short Neck</string> +<string name="Short Pigtails">Short Pigtails</string> +<string name="Short Ponytail">Short Ponytail</string> +<string name="Short Sideburns">Short Sideburns</string> +<string name="Short Torso">Short Torso</string> +<string name="Short hips">Short hips</string> +<string name="Shoulders">Shoulders</string> +<string name="Side Bangs">Side Bangs</string> +<string name="Side Bangs Down">Side Bangs Down</string> +<string name="Side Bangs Up">Side Bangs Up</string> +<string name="Side Fringe">Side Fringe</string> +<string name="Sideburns">Sideburns</string> +<string name="Sideburns bump">Sideburns bump</string> +<string name="Sides Hair">Sides Hair</string> +<string name="Sides Hair Down">Sides Hair Down</string> +<string name="Sides Hair Up">Sides Hair Up</string> +<string name="Skinny">Skinny</string> +<string name="Skinny Neck">Skinny Neck</string> +<string name="Skirt Fit">Skirt Fit</string> +<string name="Skirt Length">Skirt Length</string> +<string name="Skull">Skull</string> +<string name="Slanted Forehead">Slanted Forehead</string> +<string name="Sleeve Length">Sleeve Length</string> +<string name="Sleeve Length Cloth">Sleeve Length Cloth</string> +<string name="Sleeve Length Shadow">Sleeve Length Shadow</string> +<string name="Sleeve Length bump">Sleeve Length bump</string> +<string name="Sleeve Looseness">Sleeve Looseness</string> +<string name="Slit Back">Slit Back</string> +<string name="Slit Front">Slit Front</string> +<string name="Slit Left">Slit Left</string> +<string name="Slit Right">Slit Right</string> +<string name="Small">Small</string> +<string name="Small Hands">Small Hands</string> +<string name="Small Head">Small Head</string> +<string name="Smooth">Smooth</string> +<string name="Smooth Hair">Smooth Hair</string> +<string name="Socks Length">Socks Length</string> +<string name="Socks Length bump">Socks Length bump</string> +<string name="Some">Some</string> +<string name="Soulpatch">Soulpatch</string> +<string name="Soulpatch bump">Soulpatch bump</string> +<string name="Sparse">Sparse</string> +<string name="Spiked Hair">Spiked Hair</string> +<string name="Spine">Spine</string> +<string name="Square">Square</string> +<string name="Square Toe">Square Toe</string> +<string name="Squash Head">Squash Head</string> +<string name="Squash/Stretch Head">Squash/Stretch Head</string> +<string name="Stomach">Stomach</string> +<string name="Stretch Head">Stretch Head</string> +<string name="Sunken">Sunken</string> +<string name="Sunken Chest">Sunken Chest</string> +<string name="Sunken Eyes">Sunken Eyes</string> +<string name="Sweep Back">Sweep Back</string> +<string name="Sweep Forward">Sweep Forward</string> +<string name="Swept Back">Swept Back</string> +<string name="Swept Back Hair">Swept Back Hair</string> +<string name="Swept Forward">Swept Forward</string> +<string name="Swept Forward Hair">Swept Forward Hair</string> +<string name="Tall">Tall</string> +<string name="Taper Back">Taper Back</string> +<string name="Taper Front">Taper Front</string> +<string name="Thick Heels">Thick Heels</string> +<string name="Thick Neck">Thick Neck</string> +<string name="Thick Toe">Thick Toe</string> +<string name="Thickness">Thickness</string> +<string name="Thin">Thin</string> +<string name="Thin Eyebrows">Thin Eyebrows</string> +<string name="Thin Lips">Thin Lips</string> +<string name="Thin Nose">Thin Nose</string> +<string name="Tight Chin">Tight Chin</string> +<string name="Tight Cuffs">Tight Cuffs</string> +<string name="Tight Pants">Tight Pants</string> +<string name="Tight Shirt">Tight Shirt</string> +<string name="Tight Skirt">Tight Skirt</string> +<string name="Tight Sleeves">Tight Sleeves</string> +<string name="Tilt Left">Tilt Left</string> +<string name="Tilt Right">Tilt Right</string> +<string name="Toe Shape">Toe Shape</string> +<string name="Toe Thickness">Toe Thickness</string> +<string name="Top">Top</string> +<string name="Top Left">Top Left</string> +<string name="Top Right">Top Right</string> +<string name="Torso Length">Torso Length</string> +<string name="Torso Muscles">Torso Muscles</string> +<string name="Torso Scrawny">Torso Scrawny</string> +<string name="Unattached">Unattached</string> +<string name="Uncreased">Uncreased</string> +<string name="Underbite">Underbite</string> +<string name="Unnatural">Unnatural</string> +<string name="Upper Bridge">Upper Bridge</string> +<string name="Upper Cheeks">Upper Cheeks</string> +<string name="Upper Chin Cleft">Upper Chin Cleft</string> +<string name="Upper Clothes Shading">Upper Clothes Shading</string> +<string name="Upper Eyelid Fold">Upper Eyelid Fold</string> +<string name="Upturned">Upturned</string> +<string name="Very Red">Very Red</string> +<string name="Waist Height">Waist Height</string> +<string name="Waist Height Cloth">Waist Height Cloth</string> +<string name="Waist Height Shadow">Waist Height Shadow</string> +<string name="Well-Fed">Well-Fed</string> +<string name="White Hair">White Hair</string> +<string name="Wide">Wide</string> +<string name="Wide Back">Wide Back</string> +<string name="Wide Front">Wide Front</string> +<string name="Wide Lips">Wide Lips</string> +<string name="Wild">Wild</string> +<string name="Wrinkles">Wrinkles</string> <!-- Favorites Bar --> <string name="location_ctrl_add_landmark">Add to My Landmarks</string> diff --git a/indra/newview/skins/default/xui/en/widgets/combo_box.xml b/indra/newview/skins/default/xui/en/widgets/combo_box.xml index d7369d0726..0dbca318b6 100644 --- a/indra/newview/skins/default/xui/en/widgets/combo_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/combo_box.xml @@ -20,7 +20,9 @@ image_unselected="DropDown_Off" image_selected="DropDown_Selected" image_disabled="DropDown_Disabled" /> - <combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" /> + <combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" + background_visible="true" + /> <combo_box.combo_editor name="Combo Text Entry" select_on_focus="true" font="SansSerifSmall" /> diff --git a/indra/newview/skins/default/xui/en/widgets/expandable_text.xml b/indra/newview/skins/default/xui/en/widgets/expandable_text.xml index e470f42d36..6381dce1d6 100644 --- a/indra/newview/skins/default/xui/en/widgets/expandable_text.xml +++ b/indra/newview/skins/default/xui/en/widgets/expandable_text.xml @@ -2,6 +2,7 @@ <expandable_text max_height="300" > <textbox + more_label="More" follows="left|top" name="text" use_ellipses="true" diff --git a/indra/newview/skins/default/xui/en/widgets/scroll_list.xml b/indra/newview/skins/default/xui/en/widgets/scroll_list.xml index 824a815a99..4520768216 100644 --- a/indra/newview/skins/default/xui/en/widgets/scroll_list.xml +++ b/indra/newview/skins/default/xui/en/widgets/scroll_list.xml @@ -12,7 +12,7 @@ draw_stripes="true" scroll_bar_bg_visible="false" scroll_bar_bg_color="black" - background_visible="false" + background_visible="true" heading_height="23" draw_border="false" draw_heading="false" /> diff --git a/indra/newview/skins/default/xui/en/widgets/text.xml b/indra/newview/skins/default/xui/en/widgets/text.xml index f0127a9d5a..5914c21b2b 100644 --- a/indra/newview/skins/default/xui/en/widgets/text.xml +++ b/indra/newview/skins/default/xui/en/widgets/text.xml @@ -18,4 +18,5 @@ border_visible="false" hover="false" text_color="LabelTextColor" - v_pad="-1"/> + v_pad="-1" + max_length="4096"/> diff --git a/indra/newview/skins/default/xui/es/floater_camera.xml b/indra/newview/skins/default/xui/es/floater_camera.xml index 0246f0d440..3aeb4e5771 100644 --- a/indra/newview/skins/default/xui/es/floater_camera.xml +++ b/indra/newview/skins/default/xui/es/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="move floater" title=""> - <string name="rotate_tooltip"> +<floater name="camera_floater" title=""> + <floater.string name="rotate_tooltip"> Girar la cámara alrededor de lo enfocado - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Hacer zoom con la cámara en lo enfocado - </string> - <string name="move_tooltip"> - Mover la cámara arriba y abajo, izquierda y derecha. - </string> + </floater.string> + <floater.string name="move_tooltip"> + Mover la cámara arriba y abajo, izquierda y derecha + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Mover la cámara arriba y abajo, izquierda y derecha"/> + <joystick_zoom name="zoom" tool_tip="Hacer zoom con la cámara en lo enfocado"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/es/floater_color_picker.xml b/indra/newview/skins/default/xui/es/floater_color_picker.xml index c220c48cb0..616c373d18 100644 --- a/indra/newview/skins/default/xui/es/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/es/floater_color_picker.xml @@ -26,6 +26,6 @@ </text> <text name="(Drag below to save.)"> (Arrástrelo abajo - para guardarlo.) + para guardarlo) </text> </floater> diff --git a/indra/newview/skins/default/xui/fr/floater_camera.xml b/indra/newview/skins/default/xui/fr/floater_camera.xml index 9f280b7265..8ea640853f 100644 --- a/indra/newview/skins/default/xui/fr/floater_camera.xml +++ b/indra/newview/skins/default/xui/fr/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="move floater"> - <string name="rotate_tooltip"> +<floater name="camera_floater"> + <floater.string name="rotate_tooltip"> Faire tourner la caméra autour du point central - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Zoomer en direction du point central - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> Déplacer la caméra vers le haut et le bas, la gauche et la droite - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Déplacer la caméra vers le haut et le bas, la gauche et la droite"/> + <joystick_zoom name="zoom" tool_tip="Zoomer en direction du point central"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/fr/floater_color_picker.xml b/indra/newview/skins/default/xui/fr/floater_color_picker.xml index adab86dac0..94bcad070e 100644 --- a/indra/newview/skins/default/xui/fr/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/fr/floater_color_picker.xml @@ -27,6 +27,6 @@ </text> <text left="8" name="(Drag below to save.)" width="114"> (Faire glisser dessous -pour enregistrer.) +pour enregistrer) </text> </floater> diff --git a/indra/newview/skins/default/xui/it/floater_camera.xml b/indra/newview/skins/default/xui/it/floater_camera.xml index 9655ed2211..823be8f4a1 100644 --- a/indra/newview/skins/default/xui/it/floater_camera.xml +++ b/indra/newview/skins/default/xui/it/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="move floater" title=""> - <string name="rotate_tooltip"> +<floater name="camera_floater" title=""> + <floater.string name="rotate_tooltip"> Ruota la telecamera Intorno all'Inquadratura - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Avvicina la telecamera nell'inquadratura - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> Muovi la telecamera su e giù e a sinistra e destra - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Muovi la telecamera su e giù e a sinistra e destra"/> + <joystick_zoom name="zoom" tool_tip="Avvicina la telecamera nell'inquadratura"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/it/floater_color_picker.xml b/indra/newview/skins/default/xui/it/floater_color_picker.xml index 93188c29ac..1e6d7bc3f0 100644 --- a/indra/newview/skins/default/xui/it/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/it/floater_color_picker.xml @@ -33,6 +33,6 @@ </text> <text name="(Drag below to save.)"> (Trascina qui sotto - per salvare.) + per salvare) </text> </floater> diff --git a/indra/newview/skins/default/xui/ja/floater_camera.xml b/indra/newview/skins/default/xui/ja/floater_camera.xml index 46e7b1990d..bb87b194a4 100644 --- a/indra/newview/skins/default/xui/ja/floater_camera.xml +++ b/indra/newview/skins/default/xui/ja/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="move floater"> - <string name="rotate_tooltip"> +<floater name="camera_floater"> + <floater.string name="rotate_tooltip"> フォーカスを中心にカメラを回転 - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> フォーカスに向けてカメラをズーム - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> カメラを上下左右に移動 - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="カメラを上下左右に移動"/> + <joystick_zoom name="zoom" tool_tip="フォーカスに向けてカメラをズーム"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/nl/floater_camera.xml b/indra/newview/skins/default/xui/nl/floater_camera.xml index a6b843a0a2..81a3ed8a58 100644 --- a/indra/newview/skins/default/xui/nl/floater_camera.xml +++ b/indra/newview/skins/default/xui/nl/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="move floater" title=""> - <string name="rotate_tooltip"> +<floater name="camera_floater" title=""> + <floater.string name="rotate_tooltip"> Roteer camera rond focus - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Zoom camera naar focus - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> Beweeg camera omhoog en omlaag, links en rechts - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Beweeg camera omhoog en omlaag, links en rechts"/> + <joystick_zoom name="zoom" tool_tip="Zoom camera naar focus"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/nl/floater_color_picker.xml b/indra/newview/skins/default/xui/nl/floater_color_picker.xml index 25294e17e2..a357e874f7 100644 --- a/indra/newview/skins/default/xui/nl/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/nl/floater_color_picker.xml @@ -26,6 +26,6 @@ </text> <text name="(Drag below to save.)"> (Sleep naar beneden - om op te slaan.) + om op te slaan) </text> </floater> diff --git a/indra/newview/skins/default/xui/pl/floater_camera.xml b/indra/newview/skins/default/xui/pl/floater_camera.xml index 24da91c081..5957018144 100755 --- a/indra/newview/skins/default/xui/pl/floater_camera.xml +++ b/indra/newview/skins/default/xui/pl/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="move floater" title=""> - <string name="rotate_tooltip"> +<floater name="camera_floater" title=""> + <floater.string name="rotate_tooltip"> Obracaj kamerę wokół obiektu - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Najedź kamerą w kierunku obiektu - </string> - <string name="move_tooltip"> + </floater.string> + <floater.string name="move_tooltip"> Poruszaj kamerą w dół/górę oraz w prawo/lewo - </string> + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Poruszaj kamerą w dół/górę oraz w prawo/lewo"/> + <joystick_zoom name="zoom" tool_tip="Najedź kamerą w kierunku obiektu"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/pl/floater_color_picker.xml b/indra/newview/skins/default/xui/pl/floater_color_picker.xml index a380423cdf..d6ffe1837a 100755 --- a/indra/newview/skins/default/xui/pl/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/pl/floater_color_picker.xml @@ -26,6 +26,6 @@ Obecny Kolor: </text> <text name="(Drag below to save.)"> - (Przeciągnij tutaj.) + (Przeciągnij tutaj) </text> </floater> diff --git a/indra/newview/skins/default/xui/pt/floater_camera.xml b/indra/newview/skins/default/xui/pt/floater_camera.xml index 4dc6997606..b61e261148 100644 --- a/indra/newview/skins/default/xui/pt/floater_camera.xml +++ b/indra/newview/skins/default/xui/pt/floater_camera.xml @@ -1,12 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="move floater" title=""> - <string name="rotate_tooltip"> +<floater name="camera_floater" title=""> + <floater.string name="rotate_tooltip"> Girar a Câmera ao redor do Foco - </string> - <string name="zoom_tooltip"> + </floater.string> + <floater.string name="zoom_tooltip"> Aproximar a Câmera in direção ao Foco - </string> - <string name="move_tooltip"> - Mover a Câmera Para Cima e Para Baixo, Para a Esquerda e Para a Direita - </string> + </floater.string> + <floater.string name="move_tooltip"> + Mover a Câmera para Cima e para Baixo, para a Esquerda e para a Direita + </floater.string> + <panel name="controls"> + <joystick_track name="cam_track_stick" tool_tip="Mover a Câmera para Cima e para Baixo, para a Esquerda e para a Direita"/> + <joystick_zoom name="zoom" tool_tip="Aproximar a Câmera in direção ao Foco"/> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/pt/floater_color_picker.xml b/indra/newview/skins/default/xui/pt/floater_color_picker.xml index 95dd53ccd4..76da972b5d 100644 --- a/indra/newview/skins/default/xui/pt/floater_color_picker.xml +++ b/indra/newview/skins/default/xui/pt/floater_color_picker.xml @@ -27,6 +27,6 @@ </text> <text name="(Drag below to save.)"> (Arraste abaixo - para salvar.) + para salvar) </text> </floater> diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp new file mode 100644 index 0000000000..135c5ab501 --- /dev/null +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -0,0 +1,481 @@ +/** + * @file llmediadataclient_test.cpp + * @brief LLMediaDatClient tests + * + * $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 <iostream> +#include "../test/lltut.h" + +#include "llsdserialize.h" +#include "llerrorcontrol.h" +#include "llhttpstatuscodes.h" + +#include "../llmediadataclient.h" +#include "../llvovolume.h" + +#include "../../llprimitive/llmediaentry.cpp" +#include "../../llprimitive/lltextureentry.cpp" +#include "../../llmessage/tests/llcurl_stub.cpp" + +#include <boost/lexical_cast.hpp> + +#define VALID_OBJECT_ID "3607d5c4-644b-4a8a-871a-8b78471af2a2" +#define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111" +#define VALID_OBJECT_ID_2 "22222222-2222-2222-2222-222222222222" +#define VALID_OBJECT_ID_3 "33333333-3333-3333-3333-333333333333" +#define VALID_OBJECT_ID_4 "44444444-4444-4444-4444-444444444444" + +#define FAKE_OBJECT_MEDIA_CAP_URL "foo_ObjectMedia" +#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL "foo_ObjectMediaNavigate" +#define FAKE_OBJECT_MEDIA_CAP_URL_503 "foo_ObjectMedia_503" +#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR "foo_ObjectMediaNavigate_ERROR" + +#define MEDIA_DATA "\ +<array> \ +<string>foo</string> \ +<string>bar</string> \ +<string>baz</string> \ +</array>" + +#define _DATA_URLS(ID,DIST,INT,URL1,URL2) " \ +<llsd> \ + <map> \ + <key>uuid</key> \ + <string>" ID "</string> \ + <key>distance</key> \ + <real>" DIST "</real> \ + <key>interest</key> \ + <real>" INT "</real> \ + <key>cap_urls</key> \ + <map> \ + <key>ObjectMedia</key> \ + <string>" URL1 "</string> \ + <key>ObjectMediaNavigate</key> \ + <string>" URL2 "</string> \ + </map> \ + <key>media_data</key> \ + " MEDIA_DATA " \ + </map> \ +</llsd>" + +#define _DATA(ID,DIST,INT) _DATA_URLS(ID,DIST,INT,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL) + +const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","1.0"); + +#define STR(I) boost::lexical_cast<std::string>(I) + +#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" << \ +"================================================================================\n" << \ +"===================================== TEST " #N " ===================================\n" << \ +"================================================================================\n" << LL_ENDL; + +LLSD *gPostRecords = NULL; + +// stubs: +void LLHTTPClient::post( + const std::string& url, + const LLSD& body, + LLHTTPClient::ResponderPtr responder, + const LLSD& headers, + const F32 timeout) +{ + LLSD record; + record["url"] = url; + record["body"] = body; + record["headers"] = headers; + record["timeout"] = timeout; + gPostRecords->append(record); + + // Magic URL that triggers a 503: + if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 ) + { + responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason"); + } + else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR) + { + LLSD result; + LLSD error; + error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE; + result["error"] = error; + responder->result(result); + } + else { + responder->result(LLSD()); + } +} + +const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; + +class LLMediaDataClientObjectTest : public LLMediaDataClientObject +{ +public: + LLMediaDataClientObjectTest(const char *data) + { + std::istringstream d(data); + LLSDSerialize::fromXML(mRep, d); + mNumBounceBacks = 0; + + // std::cout << ll_pretty_print_sd(mRep) << std::endl; + // std::cout << "ID: " << getID() << std::endl; + } + LLMediaDataClientObjectTest(const LLSD &rep) + : mRep(rep), mNumBounceBacks(0) {} + ~LLMediaDataClientObjectTest() + { LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; } + + virtual U8 getMediaDataCount() const + { return mRep["media_data"].size(); } + virtual LLSD getMediaDataLLSD(U8 index) const + { return mRep["media_data"][(LLSD::Integer)index]; } + virtual LLUUID getID() const + { return mRep["uuid"]; } + virtual void mediaNavigateBounceBack(U8 index) + { + mNumBounceBacks++; + } + + virtual bool hasMedia() const + { return mRep.has("media_data"); } + + virtual void updateObjectMediaData(LLSD const &media_data_array) + { mRep["media_data"] = media_data_array; } + + virtual F64 getDistanceFromAvatar() const + { return (LLSD::Real)mRep["distance"]; } + + virtual F64 getTotalMediaInterest() const + { return (LLSD::Real)mRep["interest"]; } + + virtual std::string getCapabilityUrl(const std::string &name) const + { return mRep["cap_urls"][name]; } + + int getNumBounceBacks() const + { return mNumBounceBacks; } + +private: + LLSD mRep; + int mNumBounceBacks; +}; + + +namespace tut +{ + struct mediadataclient + { + mediadataclient() { + gPostRecords = &mLLSD; + +// LLError::setDefaultLevel(LLError::LEVEL_DEBUG); +// LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG); +// LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG); + } + LLSD mLLSD; + }; + + typedef test_group<mediadataclient> mediadataclient_t; + typedef mediadataclient_t::object mediadataclient_object_t; + tut::mediadataclient_t tut_mediadataclient("mediadataclient"); + + void ensure(const std::string &msg, int value, int expected) + { + std::string m = msg; + m += " value: " + STR(value); + m += ", expected: " + STR(expected); + ensure(m, value == expected); + } + + void ensure(const std::string &msg, const std::string & value, const std::string & expected) + { + std::string m = msg; + m += " value: " + value; + m += ", expected: " + expected; + ensure(m, value == expected); + } + + void ensure(const std::string &msg, const LLUUID & value, const LLUUID & expected) + { + std::string m = msg; + m += " value: " + value.asString(); + m += ", expected: " + expected.asString(); + ensure(m, value == expected); + } + + void ensure_llsd(const std::string &msg, const LLSD & value, const char *expected) + { + LLSD expected_llsd; + std::istringstream e(expected); + LLSDSerialize::fromXML(expected_llsd, e); + + std::string value_str = ll_pretty_print_sd(value); + std::string expected_str = ll_pretty_print_sd(expected_llsd); + std::string m = msg; + m += " value: " + value_str; + m += ", expected: " + expected_str; + ensure(m, value_str == expected_str); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + template<> template<> + void mediadataclient_object_t::test<1>() + { + // + // Test fetchMedia() + // + LOG_TEST(1); + + LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA); + int num_refs_start = o->getNumRefs(); + { + // queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick() + LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4); + mdc->fetchMedia(o); + + // Make sure no posts happened yet... + ensure("post records", gPostRecords->size(), 0); + + LLEventTimer::updateClass(); + + ensure("post records", gPostRecords->size(), 1); + ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL); + ensure("post GET", (*gPostRecords)[0]["body"]["verb"], "GET"); + ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID)); + ensure("queue empty", mdc->isEmpty()); + } + + // Make sure everyone's destroyed properly + ensure("REF COUNT", o->getNumRefs(), num_refs_start); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + template<> template<> + void mediadataclient_object_t::test<2>() + { + // + // Test updateMedia() + // + LOG_TEST(2); + + LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA); + { + // queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick() + LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4); + mdc->updateMedia(o); + ensure("post records", gPostRecords->size(), 0); + LLEventTimer::updateClass(); + + ensure("post records", gPostRecords->size(), 1); + ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL); + ensure("post UPDATE", (*gPostRecords)[0]["body"]["verb"], "UPDATE"); + ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID)); + ensure_llsd("post data llsd", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_MEDIA_DATA_KEY], + "<llsd>" MEDIA_DATA "</llsd>"); + ensure("queue empty", mdc->isEmpty()); + } + + ensure("REF COUNT", o->getNumRefs(), 1); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + template<> template<> + void mediadataclient_object_t::test<3>() + { + // + // Test navigate() + // + LOG_TEST(3); + + LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA); + { + LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4); + const char *TEST_URL = "http://example.com"; + mdc->navigate(o, 0, TEST_URL); + ensure("post records", gPostRecords->size(), 0); + LLEventTimer::updateClass(); + + // ensure no bounce back + ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0); + + ensure("post records", gPostRecords->size(), 1); + ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL); + ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID)); + ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0); + ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL); + ensure("queue empty", mdc->isEmpty()); + } + ensure("REF COUNT", o->getNumRefs(), 1); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + template<> template<> + void mediadataclient_object_t::test<4>() + { + // + // Test queue ordering + // + LOG_TEST(4); + + LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest( + _DATA(VALID_OBJECT_ID_1,"3.0","1.0")); + LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest( + _DATA(VALID_OBJECT_ID_2,"1.0","1.0")); + LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest( + _DATA(VALID_OBJECT_ID_3,"2.0","1.0")); + { + LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4); + const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 }; + mdc->fetchMedia(o1); + mdc->fetchMedia(o2); + mdc->fetchMedia(o3); + + // Make sure no posts happened yet... + ensure("post records", gPostRecords->size(), 0); + + // tick 3 times... + LLEventTimer::updateClass(); + ensure("post records", gPostRecords->size(), 1); + LLEventTimer::updateClass(); + ensure("post records", gPostRecords->size(), 2); + LLEventTimer::updateClass(); + ensure("post records", gPostRecords->size(), 3); + + for( int i=0; i < 3; i++ ) + { + ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL); + ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET"); + ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), + LLUUID(ORDERED_OBJECT_IDS[i])); + } + + ensure("queue empty", mdc->isEmpty()); + } + ensure("refcount of o1", o1->getNumRefs(), 1); + ensure("refcount of o2", o2->getNumRefs(), 1); + ensure("refcount of o3", o3->getNumRefs(), 1); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + template<> template<> + void mediadataclient_object_t::test<5>() + { + // + // Test fetchMedia() getting a 503 error + // + LOG_TEST(5); + + LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest( + _DATA_URLS(VALID_OBJECT_ID, + "1.0", + "1.0", + FAKE_OBJECT_MEDIA_CAP_URL_503, + FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)); + int num_refs_start = o->getNumRefs(); + { + const int NUM_RETRIES = 5; + LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,NUM_RETRIES); + + // This should generate a retry + mdc->fetchMedia(o); + + // Make sure no posts happened yet... + ensure("post records before", gPostRecords->size(), 0); + + // Once, causes retry + // Second, fires retry timer + // Third, fires queue timer again + for (int i=0; i<NUM_RETRIES; ++i) + { + LLEventTimer::updateClass(); + ensure("post records " + STR(i), gPostRecords->size(), i+1); + LLEventTimer::updateClass(); + } + + // Do some extre pumps to make sure no other timer work occurs. + LLEventTimer::updateClass(); + LLEventTimer::updateClass(); + LLEventTimer::updateClass(); + + // Make sure there were 2 posts + ensure("post records after", gPostRecords->size(), NUM_RETRIES); + for (int i=0; i<NUM_RETRIES; ++i) + { + ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL_503); + ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET"); + ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID)); + } + ensure("queue empty", mdc->isEmpty()); + } + + // Make sure everyone's destroyed properly + ensure("REF COUNT", o->getNumRefs(), num_refs_start); + } + + template<> template<> + void mediadataclient_object_t::test<6>() + { + // + // Test navigate() with a bounce back + // + LOG_TEST(6); + + LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest( + _DATA_URLS(VALID_OBJECT_ID, + "1.0", + "1.0", + FAKE_OBJECT_MEDIA_CAP_URL, + FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR)); + { + LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4); + const char *TEST_URL = "http://example.com"; + mdc->navigate(o, 0, TEST_URL); + ensure("post records", gPostRecords->size(), 0); + LLEventTimer::updateClass(); + + // ensure bounce back + ensure("bounce back", + dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), + 1); + + ensure("post records", gPostRecords->size(), 1); + ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR); + ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID)); + ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0); + ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL); + ensure("queue empty", mdc->isEmpty()); + } + ensure("REF COUNT", o->getNumRefs(), 1); + } + + +} diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index d3b0a2e47e..a670db699e 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -269,8 +269,8 @@ class WindowsManifest(ViewerManifest): # For google-perftools tcmalloc allocator. if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("libtcmalloc_minimal.dll") - self.end_prefix() + self.path("libtcmalloc_minimal.dll") + self.end_prefix() def nsi_file_commands(self, install=True): @@ -393,6 +393,8 @@ class WindowsManifest(ViewerManifest): # We use the Unicode version of NSIS, available from # http://www.scratchpaper.com/ NSIS_path = 'C:\\Program Files\\NSIS\\Unicode\\makensis.exe' + if not os.path.exists(NSIS_path): + NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe') self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile)) # self.remove(self.dst_path_of(tempfile)) # If we're on a build machine, sign the code using our Authenticode certificate. JC @@ -538,7 +540,7 @@ class DarwinManifest(ViewerManifest): # make sure we don't have stale files laying about self.remove(sparsename, finalname) - self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 400 -layout SPUD' % { + self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 500 -layout SPUD' % { 'sparse':sparsename, 'vol':volname}) diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 463eedb4fd..98ad8af02d 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -14,6 +14,7 @@ include(LScript) include(Linking) include(Tut) include(Boost) +include(GoogleMock) include_directories( ${LLCOMMON_INCLUDE_DIRS} @@ -24,6 +25,7 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} + ${GOOGLEMOCK_INCLUDE_DIRS} ) set(test_SOURCE_FILES @@ -126,6 +128,7 @@ target_link_libraries(test ${LLXML_LIBRARIES} ${LSCRIPT_LIBRARIES} ${LLCOMMON_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} ${APRICONV_LIBRARIES} ${PTHREAD_LIBRARY} ${WINDOWS_LIBRARIES} @@ -145,12 +148,18 @@ endif (WINDOWS) get_target_property(TEST_EXE test LOCATION) +SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR}) + +SET(TEST_LD_CMD + ${CMAKE_COMMAND} + -DLD_LIBRARY_PATH=${ARCH_PREBUILT_DIRS}:/usr/lib + -DTEST_CMD:STRING="${TEST_CMD}" + -P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake + ) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt - COMMAND ${TEST_EXE} - ARGS - --output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt - --touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt + COMMAND ${TEST_LD_CMD} DEPENDS test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "C++ unit tests" diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 2f50d872ee..721e9da917 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -54,6 +54,11 @@ # include "ctype_workaround.h" #endif +#ifndef LL_WINDOWS +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#endif + namespace tut { std::string sSourceDir; @@ -235,6 +240,11 @@ void wouldHaveCrashed(const std::string& message) int main(int argc, char **argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. +#ifndef LL_WINDOWS + ::testing::InitGoogleMock(&argc, argv); +#endif LLError::initForApplication("."); LLError::setFatalFunction(wouldHaveCrashed); LLError::setDefaultLevel(LLError::LEVEL_ERROR); diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index 7869763302..f9568a9b5d 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -2033,6 +2033,10 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e case MEDIA_EVENT_PLUGIN_FAILED: std::cerr << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << std::endl; break; + + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + std::cerr << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << std::endl; + break; } } diff --git a/install.xml b/install.xml index 6366b3104b..7c8fc5ae69 100644 --- a/install.xml +++ b/install.xml @@ -48,7 +48,7 @@ <key>copyright</key> <string>Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga</string> <key>description</key> - <string>The Simple DirectMedia Layer libraries are used for handling input and basic window/GL setup on the Linux client.</string> + <string>The Simple DirectMedia Layer libraries are used for handling input and basic window/GL setup on the Linux client. Packages also include cursors.</string> <key>license</key> <string>lgpl</string> <key>packages</key> @@ -56,23 +56,23 @@ <key>darwin</key> <map> <key>md5sum</key> - <string>7b07e7121a3623b2553ed36fb9024b40</string> + <string>40b8a63b553d91304588fba6796d7cc1</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.5-darwin-20080818.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.5-darwin-20091006.tar.bz2</uri> </map> <key>linux</key> <map> <key>md5sum</key> - <string>25f8a8fc4ea94169fe6222571b8d5e55</string> + <string>298fd8a3351f6a8d757d205a1e9ad82f</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.12-linux-20081222c.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.12-linux-20091006.tar.bz2</uri> </map> <key>windows</key> <map> <key>md5sum</key> - <string>149626b0c10d7eb8b9f9be96b5318218</string> + <string>33bb17ecbef6cdadff533d97135f3a56</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.5-windows-20080613.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.5-windows-20091006.tar.bz2</uri> </map> </map> </map> @@ -578,6 +578,39 @@ </map> </map> </map> + <key>googlemock</key> + <map> + <key>copyright</key> + <string>Copyright 2008, Google Inc.</string> + <key>description</key> + <string>Google C++ Mocking Framework (or Google Mock for short) is a library for writing and using C++ mock classes.</string> + <key>license</key> + <string>bsd</string> + <key>packages</key> + <map> + <key>darwin</key> + <map> + <key>md5sum</key> + <string>4863e9fea433d0a4be761ea5d3e8346a</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-darwin-20090626.tar.bz2</uri> + </map> + <key>linux</key> + <map> + <key>md5sum</key> + <string>877dabecf84339690191c6115c76366e</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-linux32-20090527.tar.bz2</uri> + </map> + <key>windows</key> + <map> + <key>md5sum</key> + <string>be37695d9f26552aec81c8e97ded0212</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-windows-20090529.tar.bz2</uri> + </map> + </map> + </map> <key>google-perftools</key> <map> <key>copyright</key> diff --git a/scripts/install.py b/scripts/install.py index 6278fba16c..78b8880b95 100755 --- a/scripts/install.py +++ b/scripts/install.py @@ -64,7 +64,6 @@ def add_indra_lib_path(): base_dir = add_indra_lib_path() import copy -import md5 import optparse import os import platform @@ -75,7 +74,12 @@ import tempfile import urllib2 import urlparse -from sets import Set as set, ImmutableSet as frozenset +try: + # Python 2.6 + from hashlib import md5 +except ImportError: + # Python 2.5 and earlier + from md5 import new as md5 from indra.base import llsd from indra.util import helpformatter @@ -106,7 +110,7 @@ class InstallFile(object): return "ifile{%s:%s}" % (self.pkgname, self.url) def _is_md5sum_match(self): - hasher = md5.new(file(self.filename, 'rb').read()) + hasher = md5(file(self.filename, 'rb').read()) if hasher.hexdigest() == self.md5sum: return True return False diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg index 0ddd0dbcdb..f0c6780938 100644 --- a/scripts/messages/message_template.msg +++ b/scripts/messages/message_template.msg @@ -5288,6 +5288,10 @@ version 2.0 { AgentLegacyAccess U8 } { AgentMaxAccess U8 } } + { + AgentInfo Variable + { Flags U32 } + } } // ChildAgentAlive diff --git a/scripts/update_version_files.py b/scripts/update_version_files.py index 9081941521..ee1ce69a15 100755 --- a/scripts/update_version_files.py +++ b/scripts/update_version_files.py @@ -241,23 +241,17 @@ def main(): if update_server: server_version = new_version else: - # Assume we're updating just the build number - cl = '%s info "%s"' % (svn, src_root) - status, output = _getstatusoutput(cl) - if verbose: - print - print "svn info output:" - print "----------------" - print output - - branch_match = svn_branch_re.search(output) - revision_match = svn_revision_re.search(output) - if not branch_match or not revision_match: - print "Failed to execute svn info, output follows:" - print output + + if llversion.using_svn(): + revision = llversion.get_svn_revision() + branch = llversion.get_svn_branch() + elif llversion.using_hg(): + revision = llversion.get_hg_changeset() + branch = llversion.get_hg_repo() + else: + print >>sys.stderr, "ERROR: could not determine revision and branch" return -1 - branch = branch_match.group(1) - revision = revision_match.group(1) + if skip_on_branch_re and skip_on_branch_re.match(branch): print "Release Candidate Build, leaving version files untouched." return 0 |